#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"
#define MAX_INT_LEN 11
#define STRDUP_OR_RET(to, from) \
if ((to = strdup(from)) == NULL) \
return (PWU_NOMEM);
#define STRDUP_OR_ERR(to, from, err) \
if (((to) = strdup(from)) == NULL) \
(err) = PWU_NOMEM;
#define NUM_TO_STR(to, from) \
{ \
char nb[MAX_INT_LEN]; \
if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \
return (PWU_NOMEM); \
STRDUP_OR_RET(to, nb); \
}
#define NEW_ATTR(p, i, attr, val) \
{ \
p[i] = new_attr(attr, (val)); \
if (p[i] == NULL) \
return (PWU_NOMEM); \
i++; \
}
int ldap_getattr(const char *name, attrlist *item, pwu_repository_t *rep);
int ldap_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep,
void **buf);
int ldap_update(attrlist *items, pwu_repository_t *rep, void *buf);
int ldap_putpwnam(const char *name, const char *oldpw, pwu_repository_t *rep,
void *buf);
int ldap_user_to_authenticate(const char *name, pwu_repository_t *rep,
char **auth_user, int *privileged);
struct repops ldap_repops = {
NULL,
ldap_getattr,
ldap_getpwnam,
ldap_update,
ldap_putpwnam,
ldap_user_to_authenticate,
NULL,
NULL
};
typedef struct {
char *passwd;
struct passwd *pwd;
ns_ldap_attr_t **pattrs;
int npattrs;
struct spwd *spwd;
ns_ldap_attr_t **sattrs;
int nsattrs;
boolean_t shadow_update_enabled;
} ldapbuf_t;
#define _PWD_CN "cn"
#define _PWD_UID "uid"
#define _PWD_USERPASSWORD "userpassword"
#define _PWD_UIDNUMBER "uidnumber"
#define _PWD_GIDNUMBER "gidnumber"
#define _PWD_GECOS "gecos"
#define _PWD_DESCRIPTION "description"
#define _PWD_HOMEDIRECTORY "homedirectory"
#define _PWD_LOGINSHELL "loginshell"
#define _PWD_MAX_ATTR 10
#define _S_LASTCHANGE "shadowlastchange"
#define _S_MIN "shadowmin"
#define _S_MAX "shadowmax"
#define _S_WARNING "shadowwarning"
#define _S_INACTIVE "shadowinactive"
#define _S_EXPIRE "shadowexpire"
#define _S_FLAG "shadowflag"
#define _S_MAX_ATTR 8
static void
free_ldapbuf(ldapbuf_t *p)
{
int i;
if (p == NULL)
return;
if (p->passwd) {
(void) memset(p->passwd, 0, strlen(p->passwd));
free(p->passwd);
}
if (p->pwd)
free_pwd(p->pwd);
if (p->spwd)
free_spwd(p->spwd);
if (p->pattrs) {
for (i = 0; i < p->npattrs; i++) {
if (p->pattrs[i] != NULL) {
free(p->pattrs[i]->attrvalue[0]);
free(p->pattrs[i]);
}
}
free(p->pattrs);
}
if (p->sattrs) {
for (i = 0; i < p->nsattrs; i++) {
if (p->sattrs[i] != NULL) {
free(p->sattrs[i]->attrvalue[0]);
free(p->sattrs[i]);
}
}
free(p->sattrs);
}
}
int
ldap_user_to_authenticate(const char *user, pwu_repository_t *rep,
char **auth_user, int *privileged)
{
struct passwd *pw;
uid_t uid;
uid_t priviledged_uid;
int res = PWU_SUCCESS;
if (strcmp(user, "root") == 0)
return (PWU_NOT_FOUND);
if ((pw = getpwnam_from(user, rep, REP_LDAP)) == NULL)
return (PWU_NOT_FOUND);
uid = getuid();
if (__ns_ldap_is_shadow_update_enabled()) {
boolean_t priv;
priv = (geteuid() == 0);
if (!priv) {
priv_set_t *ps = priv_allocset();
priv_set_t *zs;
(void) getppriv(PRIV_EFFECTIVE, ps);
zs = priv_str_to_set("zone", ",", NULL);
priv = priv_isequalset(ps, zs);
priv_freeset(ps);
priv_freeset(zs);
}
*privileged = 0;
if (priv) {
if (uid == 0) {
*privileged = 1;
*auth_user = NULL;
return (res);
} else if (uid == pw->pw_uid) {
STRDUP_OR_ERR(*auth_user, user, res);
return (res);
}
}
return (PWU_DENIED);
}
if (uid == pw->pw_uid) {
*privileged = 0;
STRDUP_OR_RET(*auth_user, user);
} else {
char pwd_buf[1024];
struct passwd pwr;
*privileged = 1;
if (uid == 0) {
priviledged_uid = pw->pw_uid;
} else {
priviledged_uid = uid;
}
if (getpwuid_r(priviledged_uid, &pwr, pwd_buf,
sizeof (pwd_buf)) != NULL) {
STRDUP_OR_ERR(*auth_user, pwr.pw_name, res);
} else {
if ((*auth_user = malloc(MAX_INT_LEN)) == NULL) {
res = PWU_NOMEM;
} else {
(void) snprintf(*auth_user, MAX_INT_LEN, "%d",
(int)uid);
}
}
}
return (res);
}
int
ldap_getattr(const char *name, attrlist *items, pwu_repository_t *rep)
{
attrlist *w;
int res;
ldapbuf_t *ldapbuf;
struct passwd *pw = NULL;
struct spwd *spw = NULL;
res = ldap_getpwnam(name, items, rep, (void **)&ldapbuf);
if (res != PWU_SUCCESS)
return (res);
pw = ldapbuf->pwd;
spw = ldapbuf->spwd;
for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) {
switch (w->type) {
case ATTR_NAME:
STRDUP_OR_ERR(w->data.val_s, pw->pw_name, res);
break;
case ATTR_COMMENT:
STRDUP_OR_ERR(w->data.val_s, pw->pw_comment, res);
break;
case ATTR_GECOS:
STRDUP_OR_ERR(w->data.val_s, pw->pw_gecos, res);
break;
case ATTR_HOMEDIR:
STRDUP_OR_ERR(w->data.val_s, pw->pw_dir, res);
break;
case ATTR_SHELL:
STRDUP_OR_ERR(w->data.val_s, pw->pw_shell, res);
break;
case ATTR_PASSWD:
case ATTR_PASSWD_SERVER_POLICY:
STRDUP_OR_ERR(w->data.val_s, spw->sp_pwdp, res);
break;
case ATTR_AGE:
STRDUP_OR_ERR(w->data.val_s, pw->pw_age, res);
break;
case ATTR_REP_NAME:
STRDUP_OR_ERR(w->data.val_s, "ldap", res);
break;
case ATTR_UID:
w->data.val_i = pw->pw_uid;
break;
case ATTR_GID:
w->data.val_i = pw->pw_gid;
break;
case ATTR_LSTCHG:
if (ldapbuf->shadow_update_enabled)
w->data.val_i = spw->sp_lstchg;
else
w->data.val_i = -1;
break;
case ATTR_MIN:
if (ldapbuf->shadow_update_enabled)
w->data.val_i = spw->sp_min;
else
w->data.val_i = -1;
break;
case ATTR_MAX:
if (ldapbuf->shadow_update_enabled)
w->data.val_i = spw->sp_max;
else
w->data.val_i = -1;
break;
case ATTR_WARN:
if (ldapbuf->shadow_update_enabled)
w->data.val_i = spw->sp_warn;
else
w->data.val_i = -1;
break;
case ATTR_INACT:
if (ldapbuf->shadow_update_enabled)
w->data.val_i = spw->sp_inact;
else
w->data.val_i = -1;
break;
case ATTR_EXPIRE:
if (ldapbuf->shadow_update_enabled)
w->data.val_i = spw->sp_expire;
else
w->data.val_i = -1;
break;
case ATTR_FLAG:
if (ldapbuf->shadow_update_enabled)
w->data.val_i = spw->sp_flag;
break;
case ATTR_FAILED_LOGINS:
w->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
break;
default:
break;
}
}
free_ldapbuf(ldapbuf);
free(ldapbuf);
return (res);
}
int
ldap_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep,
void **buf)
{
ldapbuf_t *ldapbuf;
int res = PWU_NOMEM;
ldapbuf = calloc(1, sizeof (ldapbuf_t));
if (ldapbuf == NULL)
return (PWU_NOMEM);
ldapbuf->pattrs = calloc(_PWD_MAX_ATTR, sizeof (ns_ldap_attr_t *));
if (ldapbuf->pattrs == NULL)
goto out;
ldapbuf->npattrs = _PWD_MAX_ATTR;
ldapbuf->sattrs = calloc(_S_MAX_ATTR, sizeof (ns_ldap_attr_t *));
if (ldapbuf->sattrs == NULL)
goto out;
ldapbuf->nsattrs = _S_MAX_ATTR;
res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
if (res != PWU_SUCCESS)
goto out;
res = dup_spw(&ldapbuf->spwd, getspnam_from(name, rep, REP_LDAP));
if (res != PWU_SUCCESS)
goto out;
else {
char *spw = ldapbuf->spwd->sp_pwdp;
if (spw != NULL && *spw != '\0') {
ldapbuf->passwd = strdup(spw);
if (ldapbuf->passwd == NULL)
goto out;
} else
ldapbuf->passwd = NULL;
}
ldapbuf->shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
*buf = (void *)ldapbuf;
return (PWU_SUCCESS);
out:
free_ldapbuf(ldapbuf);
free(ldapbuf);
return (res);
}
ns_ldap_attr_t *
new_attr(char *name, char *value)
{
ns_ldap_attr_t *tmp;
tmp = malloc(sizeof (*tmp));
if (tmp != NULL) {
tmp->attrname = name;
tmp->attrvalue = (char **)calloc(2, sizeof (char *));
if (tmp->attrvalue == NULL) {
free(tmp);
return (NULL);
}
tmp->attrvalue[0] = value;
tmp->value_count = 1;
}
return (tmp);
}
static int
max_present(attrlist *list)
{
while (list != NULL)
if (list->type == ATTR_MAX && list->data.val_i != -1)
return (1);
else
list = list->next;
return (0);
}
static int
attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value)
{
char numbuf[MAX_INT_LEN], *strp;
int i;
if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN)
return (-1);
for (i = 0; i < *idx; i++) {
if (attrs[i] != NULL &&
strcmp(item, attrs[i]->attrname) == 0) {
strp = strdup(numbuf);
if (strp == NULL)
return (-1);
free(attrs[i]->attrvalue[0]);
attrs[i]->attrvalue[0] = strp;
return (0);
}
}
strp = strdup(numbuf);
if (strp == NULL)
return (-1);
attrs[*idx] = new_attr(item, strp);
if (attrs[*idx] == NULL)
return (-1);
(*idx)++;
return (0);
}
int
ldap_update(attrlist *items, pwu_repository_t *rep, void *buf)
{
attrlist *p;
ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
struct spwd *spw;
ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
int pidx = 0;
ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
int sidx = 0;
char *pwd, *val;
char *salt;
size_t cryptlen;
int len;
int count;
int rc = PWU_SUCCESS;
int aging_needed = 0;
int aging_set = 0;
int disable_aging;
spw = ldapbuf->spwd;
disable_aging = (spw != NULL && spw->sp_max == 0 &&
ldapbuf->shadow_update_enabled);
for (p = items; p != NULL; p = p->next) {
switch (p->type) {
case ATTR_PASSWD:
if (p->data.val_s == NULL) {
if (!ldapbuf->shadow_update_enabled)
return (PWU_CHANGE_NOT_ALLOWED);
cryptlen =
sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
val = malloc(cryptlen);
if (val == NULL)
return (PWU_NOMEM);
(void) snprintf(val, cryptlen,
"{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
} else {
salt = crypt_gensalt(ldapbuf->passwd,
ldapbuf->pwd);
if (salt == NULL) {
if (errno == ENOMEM)
return (PWU_NOMEM);
syslog(LOG_AUTH | LOG_ALERT,
"passwdutil: crypt_gensalt "
"%m");
return (PWU_UPDATE_FAILED);
}
pwd = crypt(p->data.val_s, salt);
free(salt);
cryptlen = strlen(pwd) + sizeof ("{crypt}");
val = malloc(cryptlen);
if (val == NULL)
return (PWU_NOMEM);
(void) snprintf(val, cryptlen,
"{crypt}%s", pwd);
}
if (!ldapbuf->shadow_update_enabled) {
NEW_ATTR(pattrs, pidx,
_PWD_USERPASSWORD, val);
break;
}
NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, val);
if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
DAY_NOW_32) < 0)
return (PWU_NOMEM);
spw->sp_lstchg = DAY_NOW_32;
if (attr_addmod(sattrs, &sidx, _S_FLAG,
spw->sp_flag & ~FAILCOUNT_MASK) < 0)
return (PWU_NOMEM);
spw->sp_flag &= ~FAILCOUNT_MASK;
aging_needed = 1;
break;
case ATTR_PASSWD_SERVER_POLICY:
STRDUP_OR_RET(val, p->data.val_s);
NEW_ATTR(pattrs, pidx, _PWD_USERPASSWORD, val);
break;
case ATTR_COMMENT:
NEW_ATTR(pattrs, pidx, _PWD_DESCRIPTION, p->data.val_s);
break;
case ATTR_GECOS:
if (!ldapbuf->shadow_update_enabled) {
NEW_ATTR(pattrs, pidx, _PWD_GECOS,
p->data.val_s);
} else {
NEW_ATTR(sattrs, sidx, _PWD_GECOS,
p->data.val_s);
}
break;
case ATTR_HOMEDIR:
if (!ldapbuf->shadow_update_enabled) {
NEW_ATTR(pattrs, pidx, _PWD_HOMEDIRECTORY,
p->data.val_s);
} else {
NEW_ATTR(sattrs, sidx, _PWD_HOMEDIRECTORY,
p->data.val_s);
}
break;
case ATTR_SHELL:
if (!ldapbuf->shadow_update_enabled) {
NEW_ATTR(pattrs, pidx, _PWD_LOGINSHELL,
p->data.val_s);
} else {
NEW_ATTR(sattrs, sidx, _PWD_LOGINSHELL,
p->data.val_s);
}
break;
case ATTR_NAME:
case ATTR_UID:
case ATTR_GID:
case ATTR_AGE:
break;
case ATTR_LOCK_ACCOUNT:
if (!ldapbuf->shadow_update_enabled)
break;
if (spw->sp_pwdp == NULL) {
spw->sp_pwdp = LOCKSTRING;
} else if ((strncmp(spw->sp_pwdp, LOCKSTRING,
sizeof (LOCKSTRING)-1) != 0) &&
(strcmp(spw->sp_pwdp, NOLOGINSTRING) != 0)) {
len = sizeof (LOCKSTRING)-1 +
strlen(spw->sp_pwdp) + 1 +
sizeof ("{crypt}");
pwd = malloc(len);
if (pwd == NULL) {
return (PWU_NOMEM);
}
(void) strlcpy(pwd, "{crypt}", len);
(void) strlcat(pwd, LOCKSTRING, len);
(void) strlcat(pwd, spw->sp_pwdp, len);
free(spw->sp_pwdp);
spw->sp_pwdp = pwd;
NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
spw->sp_pwdp);
}
if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
DAY_NOW_32) < 0)
return (PWU_NOMEM);
spw->sp_lstchg = DAY_NOW_32;
break;
case ATTR_UNLOCK_ACCOUNT:
if (!ldapbuf->shadow_update_enabled)
break;
if (spw->sp_pwdp &&
strncmp(spw->sp_pwdp, LOCKSTRING,
sizeof (LOCKSTRING)-1) == 0) {
len = (sizeof ("{crypt}") -
sizeof (LOCKSTRING)) +
strlen(spw->sp_pwdp) + 1;
pwd = malloc(len);
if (pwd == NULL) {
return (PWU_NOMEM);
}
(void) strlcpy(pwd, "{crypt}", len);
(void) strlcat(pwd, spw->sp_pwdp +
sizeof (LOCKSTRING)-1, len);
free(spw->sp_pwdp);
spw->sp_pwdp = pwd;
NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
spw->sp_pwdp);
if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
DAY_NOW_32) < 0)
return (PWU_NOMEM);
spw->sp_lstchg = DAY_NOW_32;
}
break;
case ATTR_NOLOGIN_ACCOUNT:
if (!ldapbuf->shadow_update_enabled)
break;
free(spw->sp_pwdp);
STRDUP_OR_RET(spw->sp_pwdp, "{crypt}" NOLOGINSTRING);
NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, spw->sp_pwdp);
if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
DAY_NOW_32) < 0)
return (PWU_NOMEM);
spw->sp_lstchg = DAY_NOW_32;
break;
case ATTR_EXPIRE_PASSWORD:
if (!ldapbuf->shadow_update_enabled)
break;
NUM_TO_STR(val, 0);
NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
break;
case ATTR_LSTCHG:
if (!ldapbuf->shadow_update_enabled)
break;
NUM_TO_STR(val, p->data.val_i);
NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
break;
case ATTR_MIN:
if (!ldapbuf->shadow_update_enabled)
break;
if (spw->sp_max == -1 && p->data.val_i != -1 &&
max_present(p->next) == 0)
return (PWU_AGING_DISABLED);
NUM_TO_STR(val, p->data.val_i);
NEW_ATTR(sattrs, sidx, _S_MIN, val);
aging_set = 1;
break;
case ATTR_MAX:
if (!ldapbuf->shadow_update_enabled)
break;
if (p->data.val_i == -1) {
spw->sp_max = spw->sp_min = spw->sp_warn = -1;
NUM_TO_STR(val, -1);
NEW_ATTR(sattrs, sidx, _S_MIN, val);
NUM_TO_STR(val, -1);
NEW_ATTR(sattrs, sidx, _S_WARNING, val);
} else {
if (spw->sp_min == -1) {
spw->sp_min = 0;
NUM_TO_STR(val, 0);
NEW_ATTR(sattrs, sidx, _S_MIN,
val);
}
if (spw->sp_max == -1 &&
spw->sp_pwdp != NULL && *spw->sp_pwdp &&
spw->sp_lstchg == -1) {
if (attr_addmod(sattrs, &sidx,
_S_LASTCHANGE,
DAY_NOW_32) < 0)
return (PWU_NOMEM);
spw->sp_lstchg = DAY_NOW_32;
}
}
NUM_TO_STR(val, p->data.val_i);
NEW_ATTR(sattrs, sidx, _S_MAX, val);
aging_set = 1;
break;
case ATTR_WARN:
if (!ldapbuf->shadow_update_enabled)
break;
if (spw->sp_max == -1 &&
p->data.val_i != -1 && max_present(p->next) == 0)
return (PWU_AGING_DISABLED);
NUM_TO_STR(val, p->data.val_i);
NEW_ATTR(sattrs, sidx, _S_WARNING, val);
break;
case ATTR_INACT:
if (!ldapbuf->shadow_update_enabled)
break;
NUM_TO_STR(val, p->data.val_i);
NEW_ATTR(sattrs, sidx, _S_INACTIVE, val);
break;
case ATTR_EXPIRE:
if (!ldapbuf->shadow_update_enabled)
break;
NUM_TO_STR(val, p->data.val_i);
NEW_ATTR(sattrs, sidx, _S_EXPIRE, val);
break;
case ATTR_FLAG:
if (!ldapbuf->shadow_update_enabled)
break;
NUM_TO_STR(val, p->data.val_i);
NEW_ATTR(sattrs, sidx, _S_FLAG, val);
break;
case ATTR_INCR_FAILED_LOGINS:
if (!ldapbuf->shadow_update_enabled) {
rc = PWU_CHANGE_NOT_ALLOWED;
break;
}
count = (spw->sp_flag & FAILCOUNT_MASK) + 1;
spw->sp_flag &= ~FAILCOUNT_MASK;
spw->sp_flag |= min(FAILCOUNT_MASK, count);
p->data.val_i = count;
NUM_TO_STR(val, spw->sp_flag);
NEW_ATTR(sattrs, sidx, _S_FLAG, val);
break;
case ATTR_RST_FAILED_LOGINS:
if (!ldapbuf->shadow_update_enabled) {
rc = PWU_CHANGE_NOT_ALLOWED;
break;
}
p->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
spw->sp_flag &= ~FAILCOUNT_MASK;
NUM_TO_STR(val, spw->sp_flag);
NEW_ATTR(sattrs, sidx, _S_FLAG, val);
break;
default:
break;
}
}
if (ldapbuf->shadow_update_enabled && spw != NULL && spw->sp_max <= 0) {
if (aging_needed && !aging_set) {
if (disable_aging) {
spw->sp_min = spw->sp_max = spw->sp_warn = -1;
if (attr_addmod(sattrs, &sidx, _S_MIN, -1) < 0)
return (PWU_NOMEM);
if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0)
return (PWU_NOMEM);
if (attr_addmod(sattrs, &sidx, _S_WARNING,
-1) < 0)
return (PWU_NOMEM);
} else {
turn_on_default_aging(spw);
if (attr_addmod(sattrs, &sidx, _S_MIN,
spw->sp_min) < 0)
return (PWU_NOMEM);
if (attr_addmod(sattrs, &sidx, _S_MAX,
spw->sp_max) < 0)
return (PWU_NOMEM);
if (attr_addmod(sattrs, &sidx,
_S_WARNING, spw->sp_warn) < 0)
return (PWU_NOMEM);
}
}
}
pattrs[pidx] = NULL;
sattrs[sidx] = NULL;
return (rc);
}
int
ldap_to_pwu_code(int error, int pwd_status)
{
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);
case NS_PASSWD_CHANGE_NOT_ALLOWED:
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
ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
const char *pwd, int *pwd_status, int flags)
{
int result = NS_LDAP_OP_FAILED;
int ldaprc;
int authstried = 0;
char **certpath = NULL;
ns_auth_t **app;
ns_auth_t **authpp = NULL;
ns_auth_t *authp = NULL;
ns_cred_t *credp;
ns_ldap_error_t *errorp = NULL;
debug("%s: replace_ldapattr()", __FILE__);
if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL)
return (NS_LDAP_MEMORY);
if ((flags & NS_LDAP_UPDATE_SHADOW) == 0) {
if (dn == NULL || pwd == NULL)
goto out;
credp->cred.unix_cred.userID = strdup(binddn);
credp->cred.unix_cred.passwd = strdup(pwd);
}
ldaprc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
(void ***)&certpath, &errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
if (certpath && *certpath)
credp->hostcertpath = *certpath;
ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
&errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
if (authpp == NULL) {
ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
&errorp);
if (ldaprc != NS_LDAP_SUCCESS)
goto out;
}
if (authpp == NULL) {
syslog(LOG_ERR,
"passwdutil: no legal LDAP authentication method configured");
result = NS_LDAP_OP_FAILED;
goto out;
}
for (app = authpp; *app; app++) {
authp = *app;
if (authp->type == NS_LDAP_AUTH_NONE)
continue;
authstried++;
credp->auth.type = authp->type;
credp->auth.tlstype = authp->tlstype;
credp->auth.saslmech = authp->saslmech;
credp->auth.saslopt = authp->saslopt;
ldaprc = __ns_ldap_repAttr("shadow", dn,
(const ns_ldap_attr_t * const *)attrs,
credp, flags, &errorp);
if (ldaprc == NS_LDAP_SUCCESS) {
result = NS_LDAP_SUCCESS;
goto out;
}
if (ldaprc == NS_LDAP_CONFIG &&
errorp->status == NS_CONFIG_NOTALLOW) {
result = NS_LDAP_CONFIG;
*pwd_status = NS_PASSWD_CHANGE_NOT_ALLOWED;
goto out;
}
if ((ldaprc == NS_LDAP_INTERNAL) &&
(errorp->pwd_mgmt.status == NS_PASSWD_GOOD) &&
((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
(errorp->status == LDAP_INVALID_CREDENTIALS))) {
result = ldaprc;
goto out;
}
if ((ldaprc == NS_LDAP_INTERNAL) &&
errorp->pwd_mgmt.status != NS_PASSWD_GOOD) {
*pwd_status = errorp->pwd_mgmt.status;
result = ldaprc;
goto out;
} else
*pwd_status = NS_PASSWD_GOOD;
if (errorp)
(void) __ns_ldap_freeError(&errorp);
}
if (authstried == 0) {
syslog(LOG_ERR,
"passwdutil: no legal LDAP authentication method configured");
result = NS_LDAP_CONFIG;
goto out;
}
result = NS_LDAP_OP_FAILED;
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);
}
int
ldap_putpwnam(const char *name, const char *oldpw, pwu_repository_t *rep,
void *buf)
{
int res;
char *dn;
char *binddn;
ns_ldap_error_t *errorp;
ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
struct passwd *pw;
int pwd_status;
uid_t uid;
if (strcmp(name, "root") == 0)
return (PWU_NOT_FOUND);
res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
if (res != NS_LDAP_SUCCESS)
goto out;
if (ldapbuf->shadow_update_enabled &&
sattrs != NULL && sattrs[0] != NULL) {
res = ldap_replaceattr(dn, sattrs, NULL, NULL, &pwd_status,
NS_LDAP_UPDATE_SHADOW);
goto out;
}
uid = getuid();
if (uid == 0) {
if ((pw = getpwnam_from(name, rep, REP_LDAP)) == NULL) {
res = NS_LDAP_OP_FAILED;
goto out;
}
} else if ((pw = getpwuid_from(uid, rep, REP_LDAP)) == NULL) {
res = NS_LDAP_OP_FAILED;
goto out;
}
res = __ns_ldap_uid2dn(pw->pw_name, &binddn, NULL, &errorp);
if (res != NS_LDAP_SUCCESS)
goto out;
if (pattrs && pattrs[0] != NULL) {
res = ldap_replaceattr(dn, pattrs, binddn, oldpw,
&pwd_status, 0);
} else
res = NS_LDAP_OP_FAILED;
out:
free_ldapbuf(ldapbuf);
free(dn);
return (ldap_to_pwu_code(res, pwd_status));
}