xref: /illumos-gate/usr/src/lib/passwdutil/ldap_attr.c (revision bbf215553c7233fbab8a0afdf1fac74c44781867)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5dd1104fbSMichen Chang  * Common Development and Distribution License (the "License").
6dd1104fbSMichen Chang  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22dd1104fbSMichen Chang  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2448bbca81SDaniel Hoffman  * Copyright (c) 2016 by Delphix. All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <errno.h>
297c478bd9Sstevel@tonic-gate #include <stdlib.h>
307c478bd9Sstevel@tonic-gate #include <string.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
32dd1104fbSMichen Chang #include <macros.h>
33dd1104fbSMichen Chang #include <priv.h>
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include "ns_sldap.h"
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
387c478bd9Sstevel@tonic-gate #include <nsswitch.h>
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate #include <pwd.h>
417c478bd9Sstevel@tonic-gate #include <shadow.h>
427c478bd9Sstevel@tonic-gate #include <syslog.h>
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include "passwdutil.h"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include "utils.h"
477c478bd9Sstevel@tonic-gate 
48dd1104fbSMichen Chang #define	MAX_INT_LEN 11	/* 10+1 %d buflen for words/ints [not longs] */
49dd1104fbSMichen Chang 
50dd1104fbSMichen Chang #define	STRDUP_OR_RET(to, from) \
51dd1104fbSMichen Chang 	if ((to = strdup(from)) == NULL) \
52dd1104fbSMichen Chang 		return (PWU_NOMEM);
53dd1104fbSMichen Chang 
54dd1104fbSMichen Chang #define	STRDUP_OR_ERR(to, from, err) \
55dd1104fbSMichen Chang 	if (((to) = strdup(from)) == NULL) \
56dd1104fbSMichen Chang 		(err) = PWU_NOMEM;
57dd1104fbSMichen Chang 
58dd1104fbSMichen Chang #define	NUM_TO_STR(to, from) \
59dd1104fbSMichen Chang 	{ \
60dd1104fbSMichen Chang 		char nb[MAX_INT_LEN]; \
61dd1104fbSMichen Chang 		if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \
62dd1104fbSMichen Chang 			return (PWU_NOMEM); \
63dd1104fbSMichen Chang 		STRDUP_OR_RET(to, nb); \
64dd1104fbSMichen Chang 	}
65dd1104fbSMichen Chang 
66dd1104fbSMichen Chang #define	NEW_ATTR(p, i, attr, val) \
67dd1104fbSMichen Chang 	{ \
68dd1104fbSMichen Chang 		p[i] = new_attr(attr, (val)); \
69dd1104fbSMichen Chang 		if (p[i] == NULL) \
70dd1104fbSMichen Chang 			return (PWU_NOMEM); \
71dd1104fbSMichen Chang 		i++; \
72dd1104fbSMichen Chang 	}
73dd1104fbSMichen Chang 
747c478bd9Sstevel@tonic-gate int ldap_getattr(char *name, attrlist *item, pwu_repository_t *rep);
757c478bd9Sstevel@tonic-gate int ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
767c478bd9Sstevel@tonic-gate     void **buf);
777c478bd9Sstevel@tonic-gate int ldap_update(attrlist *items, pwu_repository_t *rep, void *buf);
7836e852a1SRaja Andra int ldap_putpwnam(char *name, char *oldpw, pwu_repository_t *rep, void *buf);
797c478bd9Sstevel@tonic-gate int ldap_user_to_authenticate(char *name, pwu_repository_t *rep,
807c478bd9Sstevel@tonic-gate 	char **auth_user, int *privileged);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate /*
837c478bd9Sstevel@tonic-gate  * ldap function pointer table, used by passwdutil_init to initialize
847c478bd9Sstevel@tonic-gate  * the global Repository-OPerations table "rops"
857c478bd9Sstevel@tonic-gate  */
867c478bd9Sstevel@tonic-gate struct repops ldap_repops = {
877c478bd9Sstevel@tonic-gate 	NULL,	/* checkhistory */
887c478bd9Sstevel@tonic-gate 	ldap_getattr,
897c478bd9Sstevel@tonic-gate 	ldap_getpwnam,
907c478bd9Sstevel@tonic-gate 	ldap_update,
917c478bd9Sstevel@tonic-gate 	ldap_putpwnam,
927c478bd9Sstevel@tonic-gate 	ldap_user_to_authenticate,
937c478bd9Sstevel@tonic-gate 	NULL,	/* lock */
947c478bd9Sstevel@tonic-gate 	NULL	/* unlock */
957c478bd9Sstevel@tonic-gate };
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
987c478bd9Sstevel@tonic-gate  * structure used to keep state between get/update/put calls
997c478bd9Sstevel@tonic-gate  */
1007c478bd9Sstevel@tonic-gate typedef struct {
1017c478bd9Sstevel@tonic-gate 	char *passwd;			/* encrypted password */
1027c478bd9Sstevel@tonic-gate 	struct passwd *pwd;
103dd1104fbSMichen Chang 	ns_ldap_attr_t **pattrs;	/* passwd attrs */
104dd1104fbSMichen Chang 	int npattrs;			/* max attrs */
105dd1104fbSMichen Chang 	struct spwd *spwd;
106dd1104fbSMichen Chang 	ns_ldap_attr_t **sattrs;	/* passwd attrs */
107dd1104fbSMichen Chang 	int nsattrs;			/* max attrs */
108dd1104fbSMichen Chang 	boolean_t shadow_update_enabled;	/* shadow update configured */
1097c478bd9Sstevel@tonic-gate } ldapbuf_t;
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /*
1127c478bd9Sstevel@tonic-gate  * The following define's are taken from
1137c478bd9Sstevel@tonic-gate  *	usr/src/lib/nsswitch/ldap/common/getpwnam.c
1147c478bd9Sstevel@tonic-gate  */
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /* passwd attributes filters */
1177c478bd9Sstevel@tonic-gate #define	_PWD_CN			"cn"
1187c478bd9Sstevel@tonic-gate #define	_PWD_UID		"uid"
1197c478bd9Sstevel@tonic-gate #define	_PWD_USERPASSWORD	"userpassword"
1207c478bd9Sstevel@tonic-gate #define	_PWD_UIDNUMBER		"uidnumber"
1217c478bd9Sstevel@tonic-gate #define	_PWD_GIDNUMBER		"gidnumber"
1227c478bd9Sstevel@tonic-gate #define	_PWD_GECOS		"gecos"
1237c478bd9Sstevel@tonic-gate #define	_PWD_DESCRIPTION	"description"
1247c478bd9Sstevel@tonic-gate #define	_PWD_HOMEDIRECTORY	"homedirectory"
1257c478bd9Sstevel@tonic-gate #define	_PWD_LOGINSHELL		"loginshell"
1267c478bd9Sstevel@tonic-gate 
127dd1104fbSMichen Chang #define	_PWD_MAX_ATTR		10	/* 9+NULL */
128dd1104fbSMichen Chang 
129dd1104fbSMichen Chang /* shadow attributes filters */
130dd1104fbSMichen Chang #define	_S_LASTCHANGE		"shadowlastchange"
131dd1104fbSMichen Chang #define	_S_MIN			"shadowmin"
132dd1104fbSMichen Chang #define	_S_MAX			"shadowmax"
133dd1104fbSMichen Chang #define	_S_WARNING		"shadowwarning"
134dd1104fbSMichen Chang #define	_S_INACTIVE		"shadowinactive"
135dd1104fbSMichen Chang #define	_S_EXPIRE		"shadowexpire"
136dd1104fbSMichen Chang #define	_S_FLAG			"shadowflag"
137dd1104fbSMichen Chang 
138dd1104fbSMichen Chang #define	_S_MAX_ATTR		8	/* 7+NULL */
139dd1104fbSMichen Chang 
140dd1104fbSMichen Chang /*
141dd1104fbSMichen Chang  * Frees up an ldapbuf_t
142dd1104fbSMichen Chang  */
143dd1104fbSMichen Chang 
144dd1104fbSMichen Chang static void
free_ldapbuf(ldapbuf_t * p)145dd1104fbSMichen Chang free_ldapbuf(ldapbuf_t *p)
146dd1104fbSMichen Chang {
147dd1104fbSMichen Chang 	int i;
148dd1104fbSMichen Chang 
149dd1104fbSMichen Chang 	if (p == NULL)
150dd1104fbSMichen Chang 		return;
151dd1104fbSMichen Chang 	if (p->passwd) {
152dd1104fbSMichen Chang 		(void) memset(p->passwd, 0, strlen(p->passwd));
153dd1104fbSMichen Chang 		free(p->passwd);
154dd1104fbSMichen Chang 	}
155dd1104fbSMichen Chang 	if (p->pwd)
156dd1104fbSMichen Chang 		free_pwd(p->pwd);
157dd1104fbSMichen Chang 	if (p->spwd)
158dd1104fbSMichen Chang 		free_spwd(p->spwd);
159dd1104fbSMichen Chang 	if (p->pattrs) {
160dd1104fbSMichen Chang 		for (i = 0; i < p->npattrs; i++) {
161dd1104fbSMichen Chang 			if (p->pattrs[i] != NULL) {
162dd1104fbSMichen Chang 				free(p->pattrs[i]->attrvalue[0]);
163dd1104fbSMichen Chang 				free(p->pattrs[i]);
164dd1104fbSMichen Chang 			}
165dd1104fbSMichen Chang 		}
166dd1104fbSMichen Chang 		free(p->pattrs);
167dd1104fbSMichen Chang 	}
168dd1104fbSMichen Chang 	if (p->sattrs) {
169dd1104fbSMichen Chang 		for (i = 0; i < p->nsattrs; i++) {
170dd1104fbSMichen Chang 			if (p->sattrs[i] != NULL) {
171dd1104fbSMichen Chang 				free(p->sattrs[i]->attrvalue[0]);
172dd1104fbSMichen Chang 				free(p->sattrs[i]);
173dd1104fbSMichen Chang 			}
174dd1104fbSMichen Chang 		}
175dd1104fbSMichen Chang 		free(p->sattrs);
176dd1104fbSMichen Chang 	}
177dd1104fbSMichen Chang }
178dd1104fbSMichen Chang 
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate  * int ldap_user_to_authenticate(user, rep, auth_user, privileged)
1817c478bd9Sstevel@tonic-gate  *
182dd1104fbSMichen Chang  * If the Shadow Update functionality is enabled, then we check to
183dd1104fbSMichen Chang  * see if the caller has 0 as the euid or has all zone privs. If so,
184*bbf21555SRichard Lowe  * the caller would be able to modify shadow(5) data stored on the
185dd1104fbSMichen Chang  * LDAP server. Otherwise, when LDAP Shadow Update is not enabled,
186dd1104fbSMichen Chang  * we can't determine whether the user is "privileged" in the LDAP
187dd1104fbSMichen Chang  * sense. The operation should be attempted and will succeed if the
188dd1104fbSMichen Chang  * user had privileges. For our purposes, we say that the user is
18948bbca81SDaniel Hoffman  * privileged if they are attempting to change another user's
190dd1104fbSMichen Chang  * password attributes.
1917c478bd9Sstevel@tonic-gate  */
1927c478bd9Sstevel@tonic-gate int
ldap_user_to_authenticate(char * user,pwu_repository_t * rep,char ** auth_user,int * privileged)1937c478bd9Sstevel@tonic-gate ldap_user_to_authenticate(char *user, pwu_repository_t *rep,
1947c478bd9Sstevel@tonic-gate 	char **auth_user, int *privileged)
1957c478bd9Sstevel@tonic-gate {
1967c478bd9Sstevel@tonic-gate 	struct passwd *pw;
1977c478bd9Sstevel@tonic-gate 	uid_t uid;
1987c478bd9Sstevel@tonic-gate 	uid_t priviledged_uid;
1997c478bd9Sstevel@tonic-gate 	int res = PWU_SUCCESS;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	if (strcmp(user, "root") == 0)
2027c478bd9Sstevel@tonic-gate 		return (PWU_NOT_FOUND);
2037c478bd9Sstevel@tonic-gate 
2047c478bd9Sstevel@tonic-gate 	if ((pw = getpwnam_from(user, rep, REP_LDAP)) == NULL)
2057c478bd9Sstevel@tonic-gate 		return (PWU_NOT_FOUND);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	uid = getuid();
2087c478bd9Sstevel@tonic-gate 
209dd1104fbSMichen Chang 	/*
210dd1104fbSMichen Chang 	 * need equivalent of write access to /etc/shadow
211dd1104fbSMichen Chang 	 * the privilege escalation model is euid == 0 || all zone privs
212dd1104fbSMichen Chang 	 */
213dd1104fbSMichen Chang 	if (__ns_ldap_is_shadow_update_enabled()) {
214dd1104fbSMichen Chang 		boolean_t priv;
215dd1104fbSMichen Chang 
216dd1104fbSMichen Chang 		priv = (geteuid() == 0);
217dd1104fbSMichen Chang 		if (!priv) {
218dd1104fbSMichen Chang 			priv_set_t *ps = priv_allocset();	/* caller */
219dd1104fbSMichen Chang 			priv_set_t *zs;				/* zone */
220dd1104fbSMichen Chang 
221dd1104fbSMichen Chang 			(void) getppriv(PRIV_EFFECTIVE, ps);
222dd1104fbSMichen Chang 			zs = priv_str_to_set("zone", ",", NULL);
223dd1104fbSMichen Chang 			priv = priv_isequalset(ps, zs);
224dd1104fbSMichen Chang 			priv_freeset(ps);
225dd1104fbSMichen Chang 			priv_freeset(zs);
226dd1104fbSMichen Chang 		}
227dd1104fbSMichen Chang 		/*
228dd1104fbSMichen Chang 		 * priv can change anyone's password,
229dd1104fbSMichen Chang 		 * only root isn't prompted.
230dd1104fbSMichen Chang 		 */
231dd1104fbSMichen Chang 		*privileged = 0;	/* for proper prompting */
232dd1104fbSMichen Chang 		if (priv) {
233dd1104fbSMichen Chang 			if (uid == 0) {
234dd1104fbSMichen Chang 				*privileged = 1;
235dd1104fbSMichen Chang 				*auth_user = NULL;
236dd1104fbSMichen Chang 				return (res);
237dd1104fbSMichen Chang 			} else if (uid == pw->pw_uid) {
238dd1104fbSMichen Chang 				STRDUP_OR_ERR(*auth_user, user, res);
239dd1104fbSMichen Chang 				return (res);
240dd1104fbSMichen Chang 			}
241dd1104fbSMichen Chang 		}
242dd1104fbSMichen Chang 
243dd1104fbSMichen Chang 		return (PWU_DENIED);
244dd1104fbSMichen Chang 	}
245dd1104fbSMichen Chang 
2467c478bd9Sstevel@tonic-gate 	if (uid == pw->pw_uid) {
247dd1104fbSMichen Chang 		/* changing our own, not privileged */
2487c478bd9Sstevel@tonic-gate 		*privileged = 0;
249dd1104fbSMichen Chang 		STRDUP_OR_RET(*auth_user, user);
2507c478bd9Sstevel@tonic-gate 	} else {
2517c478bd9Sstevel@tonic-gate 		char pwd_buf[1024];
2527c478bd9Sstevel@tonic-gate 		struct passwd pwr;
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 		*privileged = 1;
2557c478bd9Sstevel@tonic-gate 		/*
2567c478bd9Sstevel@tonic-gate 		 * specific case for root
2577c478bd9Sstevel@tonic-gate 		 * we want 'user' to be authenticated.
2587c478bd9Sstevel@tonic-gate 		 */
2597c478bd9Sstevel@tonic-gate 		if (uid == 0)  {
2607c478bd9Sstevel@tonic-gate 			priviledged_uid = pw->pw_uid;
2617c478bd9Sstevel@tonic-gate 		} else {
2627c478bd9Sstevel@tonic-gate 			priviledged_uid = uid;
2637c478bd9Sstevel@tonic-gate 		}
2647c478bd9Sstevel@tonic-gate 		if (getpwuid_r(priviledged_uid, &pwr, pwd_buf,
2657c478bd9Sstevel@tonic-gate 		    sizeof (pwd_buf)) != NULL) {
266dd1104fbSMichen Chang 			STRDUP_OR_ERR(*auth_user, pwr.pw_name, res);
2677c478bd9Sstevel@tonic-gate 		} else {
2687c478bd9Sstevel@tonic-gate 			/* hmm. can't find name of current user...??? */
2697c478bd9Sstevel@tonic-gate 
270dd1104fbSMichen Chang 			if ((*auth_user = malloc(MAX_INT_LEN)) == NULL) {
2717c478bd9Sstevel@tonic-gate 				res = PWU_NOMEM;
2727c478bd9Sstevel@tonic-gate 			} else {
273dd1104fbSMichen Chang 				(void) snprintf(*auth_user, MAX_INT_LEN, "%d",
2747c478bd9Sstevel@tonic-gate 				    (int)uid);
2757c478bd9Sstevel@tonic-gate 			}
2767c478bd9Sstevel@tonic-gate 		}
2777c478bd9Sstevel@tonic-gate 	}
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	return (res);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate  * int ldap_getattr(name, item, rep)
2847c478bd9Sstevel@tonic-gate  *
2857c478bd9Sstevel@tonic-gate  * retrieve attributes specified in "item" for user "name".
2867c478bd9Sstevel@tonic-gate  */
2877c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2887c478bd9Sstevel@tonic-gate int
ldap_getattr(char * name,attrlist * items,pwu_repository_t * rep)2897c478bd9Sstevel@tonic-gate ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep)
2907c478bd9Sstevel@tonic-gate {
291dd1104fbSMichen Chang 	attrlist *w;
2927c478bd9Sstevel@tonic-gate 	int res;
293dd1104fbSMichen Chang 	ldapbuf_t *ldapbuf;
2947c478bd9Sstevel@tonic-gate 	struct passwd *pw = NULL;
2957c478bd9Sstevel@tonic-gate 	struct spwd *spw = NULL;
2967c478bd9Sstevel@tonic-gate 
297dd1104fbSMichen Chang 	res = ldap_getpwnam(name, items, rep, (void **)&ldapbuf);
2987c478bd9Sstevel@tonic-gate 	if (res != PWU_SUCCESS)
299dd1104fbSMichen Chang 		return (res);
3007c478bd9Sstevel@tonic-gate 
301dd1104fbSMichen Chang 	pw = ldapbuf->pwd;
302dd1104fbSMichen Chang 	spw = ldapbuf->spwd;
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) {
3057c478bd9Sstevel@tonic-gate 		switch (w->type) {
3067c478bd9Sstevel@tonic-gate 		case ATTR_NAME:
307dd1104fbSMichen Chang 			STRDUP_OR_ERR(w->data.val_s, pw->pw_name, res);
3087c478bd9Sstevel@tonic-gate 			break;
3097c478bd9Sstevel@tonic-gate 		case ATTR_COMMENT:
310dd1104fbSMichen Chang 			STRDUP_OR_ERR(w->data.val_s, pw->pw_comment, res);
3117c478bd9Sstevel@tonic-gate 			break;
3127c478bd9Sstevel@tonic-gate 		case ATTR_GECOS:
313dd1104fbSMichen Chang 			STRDUP_OR_ERR(w->data.val_s, pw->pw_gecos, res);
3147c478bd9Sstevel@tonic-gate 			break;
3157c478bd9Sstevel@tonic-gate 		case ATTR_HOMEDIR:
316dd1104fbSMichen Chang 			STRDUP_OR_ERR(w->data.val_s, pw->pw_dir, res);
3177c478bd9Sstevel@tonic-gate 			break;
3187c478bd9Sstevel@tonic-gate 		case ATTR_SHELL:
319dd1104fbSMichen Chang 			STRDUP_OR_ERR(w->data.val_s, pw->pw_shell, res);
3207c478bd9Sstevel@tonic-gate 			break;
3217c478bd9Sstevel@tonic-gate 		case ATTR_PASSWD:
3227c478bd9Sstevel@tonic-gate 		case ATTR_PASSWD_SERVER_POLICY:
323dd1104fbSMichen Chang 			STRDUP_OR_ERR(w->data.val_s, spw->sp_pwdp, res);
3247c478bd9Sstevel@tonic-gate 			break;
3257c478bd9Sstevel@tonic-gate 		case ATTR_AGE:
326dd1104fbSMichen Chang 			STRDUP_OR_ERR(w->data.val_s, pw->pw_age, res);
3277c478bd9Sstevel@tonic-gate 			break;
3287c478bd9Sstevel@tonic-gate 		case ATTR_REP_NAME:
329dd1104fbSMichen Chang 			STRDUP_OR_ERR(w->data.val_s, "ldap", res);
3307c478bd9Sstevel@tonic-gate 			break;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		/* integer values */
3337c478bd9Sstevel@tonic-gate 		case ATTR_UID:
3347c478bd9Sstevel@tonic-gate 			w->data.val_i = pw->pw_uid;
3357c478bd9Sstevel@tonic-gate 			break;
3367c478bd9Sstevel@tonic-gate 		case ATTR_GID:
3377c478bd9Sstevel@tonic-gate 			w->data.val_i = pw->pw_gid;
3387c478bd9Sstevel@tonic-gate 			break;
3397c478bd9Sstevel@tonic-gate 		case ATTR_LSTCHG:
340dd1104fbSMichen Chang 			if (ldapbuf->shadow_update_enabled)
341dd1104fbSMichen Chang 				w->data.val_i = spw->sp_lstchg;
342dd1104fbSMichen Chang 			else
3437c478bd9Sstevel@tonic-gate 				w->data.val_i = -1;
3447c478bd9Sstevel@tonic-gate 			break;
3457c478bd9Sstevel@tonic-gate 		case ATTR_MIN:
346dd1104fbSMichen Chang 			if (ldapbuf->shadow_update_enabled)
347dd1104fbSMichen Chang 				w->data.val_i = spw->sp_min;
348dd1104fbSMichen Chang 			else
3497c478bd9Sstevel@tonic-gate 				w->data.val_i = -1;
3507c478bd9Sstevel@tonic-gate 			break;
3517c478bd9Sstevel@tonic-gate 		case ATTR_MAX:
352dd1104fbSMichen Chang 			if (ldapbuf->shadow_update_enabled)
353dd1104fbSMichen Chang 				w->data.val_i = spw->sp_max;
354dd1104fbSMichen Chang 			else
3557c478bd9Sstevel@tonic-gate 				w->data.val_i = -1;
3567c478bd9Sstevel@tonic-gate 			break;
3577c478bd9Sstevel@tonic-gate 		case ATTR_WARN:
358dd1104fbSMichen Chang 			if (ldapbuf->shadow_update_enabled)
359dd1104fbSMichen Chang 				w->data.val_i = spw->sp_warn;
360dd1104fbSMichen Chang 			else
3617c478bd9Sstevel@tonic-gate 				w->data.val_i = -1;
3627c478bd9Sstevel@tonic-gate 			break;
3637c478bd9Sstevel@tonic-gate 		case ATTR_INACT:
364dd1104fbSMichen Chang 			if (ldapbuf->shadow_update_enabled)
365dd1104fbSMichen Chang 				w->data.val_i = spw->sp_inact;
366dd1104fbSMichen Chang 			else
3677c478bd9Sstevel@tonic-gate 				w->data.val_i = -1;
3687c478bd9Sstevel@tonic-gate 			break;
3697c478bd9Sstevel@tonic-gate 		case ATTR_EXPIRE:
370dd1104fbSMichen Chang 			if (ldapbuf->shadow_update_enabled)
371dd1104fbSMichen Chang 				w->data.val_i = spw->sp_expire;
372dd1104fbSMichen Chang 			else
3737c478bd9Sstevel@tonic-gate 				w->data.val_i = -1;
3747c478bd9Sstevel@tonic-gate 			break;
3757c478bd9Sstevel@tonic-gate 		case ATTR_FLAG:
376dd1104fbSMichen Chang 			if (ldapbuf->shadow_update_enabled)
377dd1104fbSMichen Chang 				w->data.val_i = spw->sp_flag;
378dd1104fbSMichen Chang 			break;
379dd1104fbSMichen Chang 		case ATTR_FAILED_LOGINS:
380dd1104fbSMichen Chang 			w->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
3817c478bd9Sstevel@tonic-gate 			break;
3827c478bd9Sstevel@tonic-gate 		default:
3837c478bd9Sstevel@tonic-gate 			break;
3847c478bd9Sstevel@tonic-gate 		}
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate out:
388dd1104fbSMichen Chang 	free_ldapbuf(ldapbuf);
389dd1104fbSMichen Chang 	free(ldapbuf);
3907c478bd9Sstevel@tonic-gate 	return (res);
3917c478bd9Sstevel@tonic-gate }
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate  * int ldap_getpwnam(name, items, rep, buf)
3957c478bd9Sstevel@tonic-gate  *
3967c478bd9Sstevel@tonic-gate  * There is no need to get the old values from the ldap
3977c478bd9Sstevel@tonic-gate  * server, as the update will update each item individually.
3987c478bd9Sstevel@tonic-gate  * Therefore, we only allocate a buffer that will be used by
3997c478bd9Sstevel@tonic-gate  * _update and _putpwnam to hold the attributes to update.
4007c478bd9Sstevel@tonic-gate  *
4017c478bd9Sstevel@tonic-gate  * Only when we're about to update a password, we need to retrieve
4027c478bd9Sstevel@tonic-gate  * the old password since it contains salt-information.
4037c478bd9Sstevel@tonic-gate  */
4047c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4057c478bd9Sstevel@tonic-gate int
ldap_getpwnam(char * name,attrlist * items,pwu_repository_t * rep,void ** buf)4067c478bd9Sstevel@tonic-gate ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep,
4077c478bd9Sstevel@tonic-gate     void **buf)
4087c478bd9Sstevel@tonic-gate {
4097c478bd9Sstevel@tonic-gate 	ldapbuf_t *ldapbuf;
410dd1104fbSMichen Chang 	int res = PWU_NOMEM;
4117c478bd9Sstevel@tonic-gate 
412dd1104fbSMichen Chang 	/*
413dd1104fbSMichen Chang 	 * [sp]attrs is treated as NULL terminated
414dd1104fbSMichen Chang 	 */
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate 	ldapbuf = calloc(1, sizeof (ldapbuf_t));
4177c478bd9Sstevel@tonic-gate 	if (ldapbuf == NULL)
4187c478bd9Sstevel@tonic-gate 		return (PWU_NOMEM);
4197c478bd9Sstevel@tonic-gate 
420dd1104fbSMichen Chang 	ldapbuf->pattrs = calloc(_PWD_MAX_ATTR, sizeof (ns_ldap_attr_t *));
421dd1104fbSMichen Chang 	if (ldapbuf->pattrs == NULL)
422dd1104fbSMichen Chang 		goto out;
423dd1104fbSMichen Chang 	ldapbuf->npattrs = _PWD_MAX_ATTR;
4247c478bd9Sstevel@tonic-gate 
425dd1104fbSMichen Chang 	ldapbuf->sattrs = calloc(_S_MAX_ATTR, sizeof (ns_ldap_attr_t *));
426dd1104fbSMichen Chang 	if (ldapbuf->sattrs == NULL)
427dd1104fbSMichen Chang 		goto out;
428dd1104fbSMichen Chang 	ldapbuf->nsattrs = _S_MAX_ATTR;
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate 	res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
4317c478bd9Sstevel@tonic-gate 	if (res != PWU_SUCCESS)
432dd1104fbSMichen Chang 		goto out;
4337c478bd9Sstevel@tonic-gate 
434dd1104fbSMichen Chang 	res = dup_spw(&ldapbuf->spwd, getspnam_from(name, rep, REP_LDAP));
435dd1104fbSMichen Chang 	if (res != PWU_SUCCESS)
436dd1104fbSMichen Chang 		goto out;
437dd1104fbSMichen Chang 	else {
438dd1104fbSMichen Chang 		char *spw = ldapbuf->spwd->sp_pwdp;
439dd1104fbSMichen Chang 		if (spw != NULL && *spw != '\0') {
440dd1104fbSMichen Chang 			ldapbuf->passwd = strdup(spw);
4417c478bd9Sstevel@tonic-gate 			if (ldapbuf->passwd == NULL)
442dd1104fbSMichen Chang 				goto out;
443dd1104fbSMichen Chang 		} else
444dd1104fbSMichen Chang 			ldapbuf->passwd = NULL;
4457c478bd9Sstevel@tonic-gate 	}
4467c478bd9Sstevel@tonic-gate 
447dd1104fbSMichen Chang 	/* remember if shadow update is enabled */
448dd1104fbSMichen Chang 	ldapbuf->shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
449dd1104fbSMichen Chang 
450dd1104fbSMichen Chang 	*buf = (void *)ldapbuf;
451dd1104fbSMichen Chang 	return (PWU_SUCCESS);
452dd1104fbSMichen Chang 
453dd1104fbSMichen Chang out:
454dd1104fbSMichen Chang 	free_ldapbuf(ldapbuf);
455dd1104fbSMichen Chang 	free(ldapbuf);
456dd1104fbSMichen Chang 	return (res);
4577c478bd9Sstevel@tonic-gate }
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate /*
4607c478bd9Sstevel@tonic-gate  * new_attr(name, value)
4617c478bd9Sstevel@tonic-gate  *
4627c478bd9Sstevel@tonic-gate  * create a new LDAP attribute to be sent to the server
4637c478bd9Sstevel@tonic-gate  */
4647c478bd9Sstevel@tonic-gate ns_ldap_attr_t *
new_attr(char * name,char * value)4657c478bd9Sstevel@tonic-gate new_attr(char *name, char *value)
4667c478bd9Sstevel@tonic-gate {
4677c478bd9Sstevel@tonic-gate 	ns_ldap_attr_t *tmp;
4687c478bd9Sstevel@tonic-gate 
4697c478bd9Sstevel@tonic-gate 	tmp = malloc(sizeof (*tmp));
4707c478bd9Sstevel@tonic-gate 	if (tmp != NULL) {
4717c478bd9Sstevel@tonic-gate 		tmp->attrname = name;
4727c478bd9Sstevel@tonic-gate 		tmp->attrvalue = (char **)calloc(2, sizeof (char *));
4737c478bd9Sstevel@tonic-gate 		if (tmp->attrvalue == NULL) {
4747c478bd9Sstevel@tonic-gate 			free(tmp);
4757c478bd9Sstevel@tonic-gate 			return (NULL);
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 		tmp->attrvalue[0] = value;
4787c478bd9Sstevel@tonic-gate 		tmp->value_count = 1;
4797c478bd9Sstevel@tonic-gate 	}
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 	return (tmp);
4827c478bd9Sstevel@tonic-gate }
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate /*
485dd1104fbSMichen Chang  * max_present(list)
486dd1104fbSMichen Chang  *
487dd1104fbSMichen Chang  * returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
488dd1104fbSMichen Chang  * if password aging is to be turned on).
489dd1104fbSMichen Chang  */
490dd1104fbSMichen Chang static int
max_present(attrlist * list)491dd1104fbSMichen Chang max_present(attrlist *list)
492dd1104fbSMichen Chang {
493dd1104fbSMichen Chang 	while (list != NULL)
494dd1104fbSMichen Chang 		if (list->type == ATTR_MAX && list->data.val_i != -1)
495dd1104fbSMichen Chang 			return (1);
496dd1104fbSMichen Chang 		else
497dd1104fbSMichen Chang 			list = list->next;
498dd1104fbSMichen Chang 	return (0);
499dd1104fbSMichen Chang }
500dd1104fbSMichen Chang 
501dd1104fbSMichen Chang /*
502dd1104fbSMichen Chang  * attr_addmod(attrs, idx, item, val)
503dd1104fbSMichen Chang  *
504dd1104fbSMichen Chang  * Adds or updates attribute 'item' in ldap_attrs list to value
505dd1104fbSMichen Chang  * update idx if item is added
506dd1104fbSMichen Chang  * return:  -1 - PWU_NOMEM/error, 0 - success
507dd1104fbSMichen Chang  */
508dd1104fbSMichen Chang static int
attr_addmod(ns_ldap_attr_t ** attrs,int * idx,char * item,int value)509dd1104fbSMichen Chang attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value)
510dd1104fbSMichen Chang {
511dd1104fbSMichen Chang 	char numbuf[MAX_INT_LEN], *strp;
512dd1104fbSMichen Chang 	int i;
513dd1104fbSMichen Chang 
514dd1104fbSMichen Chang 	/* stringize the value or abort */
515dd1104fbSMichen Chang 	if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN)
516dd1104fbSMichen Chang 		return (-1);
517dd1104fbSMichen Chang 
518dd1104fbSMichen Chang 	/* check for existence and modify existing */
519dd1104fbSMichen Chang 	for (i = 0; i < *idx; i++) {
520dd1104fbSMichen Chang 		if (attrs[i] != NULL &&
521dd1104fbSMichen Chang 		    strcmp(item, attrs[i]->attrname) == 0) {
522dd1104fbSMichen Chang 			strp = strdup(numbuf);
523dd1104fbSMichen Chang 			if (strp == NULL)
524dd1104fbSMichen Chang 				return (-1);
525dd1104fbSMichen Chang 			free(attrs[i]->attrvalue[0]);
526dd1104fbSMichen Chang 			attrs[i]->attrvalue[0] = strp;
527dd1104fbSMichen Chang 			return (0);
528dd1104fbSMichen Chang 		}
529dd1104fbSMichen Chang 	}
530dd1104fbSMichen Chang 	/* else add */
531dd1104fbSMichen Chang 	strp = strdup(numbuf);
532dd1104fbSMichen Chang 	if (strp == NULL)
533dd1104fbSMichen Chang 		return (-1);
534dd1104fbSMichen Chang 	attrs[*idx] = new_attr(item, strp);
535dd1104fbSMichen Chang 	if (attrs[*idx] == NULL)
536dd1104fbSMichen Chang 		return (-1);
537dd1104fbSMichen Chang 	(*idx)++;
538dd1104fbSMichen Chang 	return (0);
539dd1104fbSMichen Chang }
540dd1104fbSMichen Chang 
541dd1104fbSMichen Chang /*
5427c478bd9Sstevel@tonic-gate  * ldap_update(items, rep, buf)
5437c478bd9Sstevel@tonic-gate  *
5447c478bd9Sstevel@tonic-gate  * create LDAP attributes in 'buf' for each attribute in 'items'.
5457c478bd9Sstevel@tonic-gate  */
5467c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5477c478bd9Sstevel@tonic-gate int
ldap_update(attrlist * items,pwu_repository_t * rep,void * buf)5487c478bd9Sstevel@tonic-gate ldap_update(attrlist *items, pwu_repository_t *rep, void *buf)
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate 	attrlist *p;
5517c478bd9Sstevel@tonic-gate 	ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
552dd1104fbSMichen Chang 	struct spwd *spw;
553dd1104fbSMichen Chang 	ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
554dd1104fbSMichen Chang 	int pidx = 0;
555dd1104fbSMichen Chang 	ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
556dd1104fbSMichen Chang 	int sidx = 0;
5577c478bd9Sstevel@tonic-gate 	char *pwd, *val;
5587c478bd9Sstevel@tonic-gate 	char *salt;
5597c478bd9Sstevel@tonic-gate 	size_t cryptlen;
560dd1104fbSMichen Chang 	int len;
561dd1104fbSMichen Chang 	int count;
562dd1104fbSMichen Chang 	int rc = PWU_SUCCESS;
563dd1104fbSMichen Chang 	int aging_needed = 0;
564dd1104fbSMichen Chang 	int aging_set = 0;
565dd1104fbSMichen Chang 	int disable_aging;
566dd1104fbSMichen Chang 
567dd1104fbSMichen Chang 	spw = ldapbuf->spwd;
568dd1104fbSMichen Chang 
569dd1104fbSMichen Chang 	/*
570dd1104fbSMichen Chang 	 * if sp_max==0 and shadow update is enabled:
571dd1104fbSMichen Chang 	 * disable passwd aging after updating the password
572dd1104fbSMichen Chang 	 */
573dd1104fbSMichen Chang 	disable_aging = (spw != NULL && spw->sp_max == 0 &&
574dd1104fbSMichen Chang 	    ldapbuf->shadow_update_enabled);
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate 	for (p = items; p != NULL; p = p->next) {
5777c478bd9Sstevel@tonic-gate 		switch (p->type) {
5787c478bd9Sstevel@tonic-gate 		case ATTR_PASSWD:
579dd1104fbSMichen Chang 			/*
580dd1104fbSMichen Chang 			 * There is a special case for ldap: if the
581dd1104fbSMichen Chang 			 * password is to be deleted (-d to passwd),
582dd1104fbSMichen Chang 			 * p->data.val_s will be NULL.
583dd1104fbSMichen Chang 			 */
584dd1104fbSMichen Chang 			if (p->data.val_s == NULL) {
585dd1104fbSMichen Chang 				if (!ldapbuf->shadow_update_enabled)
586dd1104fbSMichen Chang 					return (PWU_CHANGE_NOT_ALLOWED);
587dd1104fbSMichen Chang 				cryptlen =
588dd1104fbSMichen Chang 				    sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
589dd1104fbSMichen Chang 				val = malloc(cryptlen);
590dd1104fbSMichen Chang 				if (val == NULL)
591dd1104fbSMichen Chang 					return (PWU_NOMEM);
592dd1104fbSMichen Chang 				(void) snprintf(val, cryptlen,
593dd1104fbSMichen Chang 				"{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
594dd1104fbSMichen Chang 			} else { /* not deleting password */
595dd1104fbSMichen Chang 				salt = crypt_gensalt(ldapbuf->passwd,
596dd1104fbSMichen Chang 				    ldapbuf->pwd);
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 				if (salt == NULL) {
5997c478bd9Sstevel@tonic-gate 					if (errno == ENOMEM)
6007c478bd9Sstevel@tonic-gate 						return (PWU_NOMEM);
601dd1104fbSMichen Chang 
6027c478bd9Sstevel@tonic-gate 					/* algorithm problem? */
6037c478bd9Sstevel@tonic-gate 					syslog(LOG_AUTH | LOG_ALERT,
6047c478bd9Sstevel@tonic-gate 					    "passwdutil: crypt_gensalt "
6057c478bd9Sstevel@tonic-gate 					    "%m");
6067c478bd9Sstevel@tonic-gate 					return (PWU_UPDATE_FAILED);
6077c478bd9Sstevel@tonic-gate 				}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 				pwd = crypt(p->data.val_s, salt);
6107c478bd9Sstevel@tonic-gate 				free(salt);
6117c478bd9Sstevel@tonic-gate 				cryptlen = strlen(pwd) + sizeof ("{crypt}");
6127c478bd9Sstevel@tonic-gate 				val = malloc(cryptlen);
6137c478bd9Sstevel@tonic-gate 				if (val == NULL)
6147c478bd9Sstevel@tonic-gate 					return (PWU_NOMEM);
615dd1104fbSMichen Chang 				(void) snprintf(val, cryptlen,
616dd1104fbSMichen Chang 				    "{crypt}%s", pwd);
617dd1104fbSMichen Chang 			}
6187c478bd9Sstevel@tonic-gate 
619dd1104fbSMichen Chang 			/*
620dd1104fbSMichen Chang 			 * If not managing passwordAccount,
621dd1104fbSMichen Chang 			 * insert the new password in the
622dd1104fbSMichen Chang 			 * passwd attr array and break.
623dd1104fbSMichen Chang 			 */
624dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled) {
625dd1104fbSMichen Chang 				NEW_ATTR(pattrs, pidx,
626dd1104fbSMichen Chang 				    _PWD_USERPASSWORD, val);
6277c478bd9Sstevel@tonic-gate 				break;
628dd1104fbSMichen Chang 			}
629dd1104fbSMichen Chang 
630dd1104fbSMichen Chang 			/*
631dd1104fbSMichen Chang 			 * Managing passwordAccount, insert the
632dd1104fbSMichen Chang 			 * new password, along with lastChange and
633dd1104fbSMichen Chang 			 * shadowFlag, in the shadow attr array.
634dd1104fbSMichen Chang 			 */
635dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, val);
636dd1104fbSMichen Chang 
637dd1104fbSMichen Chang 			if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
638dd1104fbSMichen Chang 			    DAY_NOW_32) < 0)
639dd1104fbSMichen Chang 				return (PWU_NOMEM);
640dd1104fbSMichen Chang 			spw->sp_lstchg = DAY_NOW_32;
641dd1104fbSMichen Chang 
642dd1104fbSMichen Chang 			if (attr_addmod(sattrs, &sidx, _S_FLAG,
643dd1104fbSMichen Chang 			    spw->sp_flag & ~FAILCOUNT_MASK) < 0)
644dd1104fbSMichen Chang 				return (PWU_NOMEM);
645dd1104fbSMichen Chang 			spw->sp_flag &= ~FAILCOUNT_MASK; /* reset count */
646dd1104fbSMichen Chang 			aging_needed = 1;
647dd1104fbSMichen Chang 			break;
648dd1104fbSMichen Chang 		case ATTR_PASSWD_SERVER_POLICY:
6497c478bd9Sstevel@tonic-gate 			/*
6507c478bd9Sstevel@tonic-gate 			 * For server policy, don't crypt the password,
6517c478bd9Sstevel@tonic-gate 			 * send the password as is to the server and
6527c478bd9Sstevel@tonic-gate 			 * let the LDAP server do its own password
6537c478bd9Sstevel@tonic-gate 			 * encryption
6547c478bd9Sstevel@tonic-gate 			 */
655dd1104fbSMichen Chang 			STRDUP_OR_RET(val, p->data.val_s);
6567c478bd9Sstevel@tonic-gate 
657dd1104fbSMichen Chang 			NEW_ATTR(pattrs, pidx, _PWD_USERPASSWORD, val);
6587c478bd9Sstevel@tonic-gate 			break;
6597c478bd9Sstevel@tonic-gate 		case ATTR_COMMENT:
6607c478bd9Sstevel@tonic-gate 			/* XX correct? */
661dd1104fbSMichen Chang 			NEW_ATTR(pattrs, pidx, _PWD_DESCRIPTION, p->data.val_s);
6627c478bd9Sstevel@tonic-gate 			break;
6637c478bd9Sstevel@tonic-gate 		case ATTR_GECOS:
664dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled) {
665dd1104fbSMichen Chang 				NEW_ATTR(pattrs, pidx, _PWD_GECOS,
666dd1104fbSMichen Chang 				    p->data.val_s);
667dd1104fbSMichen Chang 			} else {
668dd1104fbSMichen Chang 				NEW_ATTR(sattrs, sidx, _PWD_GECOS,
669dd1104fbSMichen Chang 				    p->data.val_s);
670dd1104fbSMichen Chang 			}
6717c478bd9Sstevel@tonic-gate 			break;
6727c478bd9Sstevel@tonic-gate 		case ATTR_HOMEDIR:
673dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled) {
674dd1104fbSMichen Chang 				NEW_ATTR(pattrs, pidx, _PWD_HOMEDIRECTORY,
6757c478bd9Sstevel@tonic-gate 				    p->data.val_s);
676dd1104fbSMichen Chang 			} else {
677dd1104fbSMichen Chang 				NEW_ATTR(sattrs, sidx, _PWD_HOMEDIRECTORY,
678dd1104fbSMichen Chang 				    p->data.val_s);
679dd1104fbSMichen Chang 			}
6807c478bd9Sstevel@tonic-gate 			break;
6817c478bd9Sstevel@tonic-gate 		case ATTR_SHELL:
682dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled) {
683dd1104fbSMichen Chang 				NEW_ATTR(pattrs, pidx, _PWD_LOGINSHELL,
684dd1104fbSMichen Chang 				    p->data.val_s);
685dd1104fbSMichen Chang 			} else {
686dd1104fbSMichen Chang 				NEW_ATTR(sattrs, sidx, _PWD_LOGINSHELL,
687dd1104fbSMichen Chang 				    p->data.val_s);
688dd1104fbSMichen Chang 			}
6897c478bd9Sstevel@tonic-gate 			break;
690dd1104fbSMichen Chang 		/* We don't update NAME, UID, GID */
6917c478bd9Sstevel@tonic-gate 		case ATTR_NAME:
6927c478bd9Sstevel@tonic-gate 		case ATTR_UID:
6937c478bd9Sstevel@tonic-gate 		case ATTR_GID:
694dd1104fbSMichen Chang 		/* Unsupported item */
6957c478bd9Sstevel@tonic-gate 		case ATTR_AGE:
696dd1104fbSMichen Chang 			break;
697dd1104fbSMichen Chang 		case ATTR_LOCK_ACCOUNT:
698dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
699dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
700dd1104fbSMichen Chang 			if (spw->sp_pwdp == NULL) {
701dd1104fbSMichen Chang 				spw->sp_pwdp = LOCKSTRING;
7025477a4d9Sgww 			} else if ((strncmp(spw->sp_pwdp, LOCKSTRING,
7035477a4d9Sgww 			    sizeof (LOCKSTRING)-1) != 0) &&
7045477a4d9Sgww 			    (strcmp(spw->sp_pwdp, NOLOGINSTRING) != 0)) {
705dd1104fbSMichen Chang 				len = sizeof (LOCKSTRING)-1 +
706dd1104fbSMichen Chang 				    strlen(spw->sp_pwdp) + 1 +
707dd1104fbSMichen Chang 				    sizeof ("{crypt}");
708dd1104fbSMichen Chang 				pwd = malloc(len);
709dd1104fbSMichen Chang 				if (pwd == NULL) {
710dd1104fbSMichen Chang 					return (PWU_NOMEM);
711dd1104fbSMichen Chang 				}
712dd1104fbSMichen Chang 				(void) strlcpy(pwd, "{crypt}", len);
713dd1104fbSMichen Chang 				(void) strlcat(pwd, LOCKSTRING, len);
714dd1104fbSMichen Chang 				(void) strlcat(pwd, spw->sp_pwdp, len);
715dd1104fbSMichen Chang 				free(spw->sp_pwdp);
716dd1104fbSMichen Chang 				spw->sp_pwdp = pwd;
717dd1104fbSMichen Chang 				NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
718dd1104fbSMichen Chang 				    spw->sp_pwdp);
719dd1104fbSMichen Chang 			}
720dd1104fbSMichen Chang 			if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
721dd1104fbSMichen Chang 			    DAY_NOW_32) < 0)
722dd1104fbSMichen Chang 				return (PWU_NOMEM);
723dd1104fbSMichen Chang 			spw->sp_lstchg = DAY_NOW_32;
724dd1104fbSMichen Chang 			break;
725dd1104fbSMichen Chang 
726dd1104fbSMichen Chang 		case ATTR_UNLOCK_ACCOUNT:
727dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
728dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
729dd1104fbSMichen Chang 			if (spw->sp_pwdp &&
730dd1104fbSMichen Chang 			    strncmp(spw->sp_pwdp, LOCKSTRING,
731dd1104fbSMichen Chang 			    sizeof (LOCKSTRING)-1) == 0) {
732dd1104fbSMichen Chang 				len = (sizeof ("{crypt}") -
733dd1104fbSMichen Chang 				    sizeof (LOCKSTRING)) +
734dd1104fbSMichen Chang 				    strlen(spw->sp_pwdp) + 1;
735dd1104fbSMichen Chang 				pwd = malloc(len);
736dd1104fbSMichen Chang 				if (pwd == NULL) {
737dd1104fbSMichen Chang 					return (PWU_NOMEM);
738dd1104fbSMichen Chang 				}
739dd1104fbSMichen Chang 				(void) strlcpy(pwd, "{crypt}", len);
740dd1104fbSMichen Chang 				(void) strlcat(pwd, spw->sp_pwdp +
741dd1104fbSMichen Chang 				    sizeof (LOCKSTRING)-1, len);
742dd1104fbSMichen Chang 				free(spw->sp_pwdp);
743dd1104fbSMichen Chang 				spw->sp_pwdp = pwd;
744dd1104fbSMichen Chang 
745dd1104fbSMichen Chang 				NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
746dd1104fbSMichen Chang 				    spw->sp_pwdp);
747dd1104fbSMichen Chang 				if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
748dd1104fbSMichen Chang 				    DAY_NOW_32) < 0)
749dd1104fbSMichen Chang 					return (PWU_NOMEM);
750dd1104fbSMichen Chang 				spw->sp_lstchg = DAY_NOW_32;
751dd1104fbSMichen Chang 			}
752dd1104fbSMichen Chang 			break;
753dd1104fbSMichen Chang 
754dd1104fbSMichen Chang 		case ATTR_NOLOGIN_ACCOUNT:
755dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
756dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
757dd1104fbSMichen Chang 			free(spw->sp_pwdp);
758dd1104fbSMichen Chang 			STRDUP_OR_RET(spw->sp_pwdp, "{crypt}" NOLOGINSTRING);
759dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, spw->sp_pwdp);
760dd1104fbSMichen Chang 			if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
761dd1104fbSMichen Chang 			    DAY_NOW_32) < 0)
762dd1104fbSMichen Chang 				return (PWU_NOMEM);
763dd1104fbSMichen Chang 			spw->sp_lstchg = DAY_NOW_32;
764dd1104fbSMichen Chang 			break;
765dd1104fbSMichen Chang 
766dd1104fbSMichen Chang 		case ATTR_EXPIRE_PASSWORD:
767dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
768dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
769dd1104fbSMichen Chang 			NUM_TO_STR(val, 0);
770dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
771dd1104fbSMichen Chang 			break;
772dd1104fbSMichen Chang 
7737c478bd9Sstevel@tonic-gate 		case ATTR_LSTCHG:
774dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
775dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
776dd1104fbSMichen Chang 			NUM_TO_STR(val, p->data.val_i);
777dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
778dd1104fbSMichen Chang 			break;
779dd1104fbSMichen Chang 
7807c478bd9Sstevel@tonic-gate 		case ATTR_MIN:
781dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
782dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
783dd1104fbSMichen Chang 			if (spw->sp_max == -1 && p->data.val_i != -1 &&
784dd1104fbSMichen Chang 			    max_present(p->next) == 0)
785dd1104fbSMichen Chang 				return (PWU_AGING_DISABLED);
786dd1104fbSMichen Chang 			NUM_TO_STR(val, p->data.val_i);
787dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_MIN, val);
788dd1104fbSMichen Chang 			aging_set = 1;
789dd1104fbSMichen Chang 			break;
790dd1104fbSMichen Chang 
7917c478bd9Sstevel@tonic-gate 		case ATTR_MAX:
792dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
793dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
794dd1104fbSMichen Chang 			if (p->data.val_i == -1) {
795dd1104fbSMichen Chang 				/* Turn off aging. Reset min and warn too */
796dd1104fbSMichen Chang 				spw->sp_max = spw->sp_min = spw->sp_warn = -1;
797dd1104fbSMichen Chang 				NUM_TO_STR(val, -1);
798dd1104fbSMichen Chang 				NEW_ATTR(sattrs, sidx, _S_MIN, val);
799dd1104fbSMichen Chang 				NUM_TO_STR(val, -1);
800dd1104fbSMichen Chang 				NEW_ATTR(sattrs, sidx, _S_WARNING, val);
801dd1104fbSMichen Chang 			} else {
802dd1104fbSMichen Chang 				/* Turn account aging on */
803dd1104fbSMichen Chang 				if (spw->sp_min == -1) {
804dd1104fbSMichen Chang 					/*
805dd1104fbSMichen Chang 					 * minage was not set with command-
806dd1104fbSMichen Chang 					 * line option: set to zero
807dd1104fbSMichen Chang 					 */
808dd1104fbSMichen Chang 					spw->sp_min = 0;
809dd1104fbSMichen Chang 					NUM_TO_STR(val, 0);
810dd1104fbSMichen Chang 					NEW_ATTR(sattrs, sidx, _S_MIN,
811dd1104fbSMichen Chang 					    val);
812dd1104fbSMichen Chang 				}
813dd1104fbSMichen Chang 				/*
814dd1104fbSMichen Chang 				 * If aging was turned off, we update lstchg.
815dd1104fbSMichen Chang 				 * We take care not to update lstchg if the
816dd1104fbSMichen Chang 				 * user has no password, otherwise the user
817dd1104fbSMichen Chang 				 * might not be required to provide a password
81848bbca81SDaniel Hoffman 				 * the next time they log in.
819dd1104fbSMichen Chang 				 *
820dd1104fbSMichen Chang 				 * Also, if lstchg != -1 (i.e., not set)
821dd1104fbSMichen Chang 				 * we keep the old value.
822dd1104fbSMichen Chang 				 */
823dd1104fbSMichen Chang 				if (spw->sp_max == -1 &&
824dd1104fbSMichen Chang 				    spw->sp_pwdp != NULL && *spw->sp_pwdp &&
825dd1104fbSMichen Chang 				    spw->sp_lstchg == -1) {
826dd1104fbSMichen Chang 					if (attr_addmod(sattrs, &sidx,
827dd1104fbSMichen Chang 					    _S_LASTCHANGE,
828dd1104fbSMichen Chang 					    DAY_NOW_32) < 0)
829dd1104fbSMichen Chang 						return (PWU_NOMEM);
830dd1104fbSMichen Chang 					spw->sp_lstchg = DAY_NOW_32;
831dd1104fbSMichen Chang 				}
832dd1104fbSMichen Chang 			}
833dd1104fbSMichen Chang 			NUM_TO_STR(val, p->data.val_i);
834dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_MAX, val);
835dd1104fbSMichen Chang 			aging_set = 1;
836dd1104fbSMichen Chang 			break;
837dd1104fbSMichen Chang 
8387c478bd9Sstevel@tonic-gate 		case ATTR_WARN:
839dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
840dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
841dd1104fbSMichen Chang 			if (spw->sp_max == -1 &&
842dd1104fbSMichen Chang 			    p->data.val_i != -1 && max_present(p->next) == 0)
843dd1104fbSMichen Chang 				return (PWU_AGING_DISABLED);
844dd1104fbSMichen Chang 			NUM_TO_STR(val, p->data.val_i);
845dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_WARNING, val);
846dd1104fbSMichen Chang 			break;
847dd1104fbSMichen Chang 
8487c478bd9Sstevel@tonic-gate 		case ATTR_INACT:
849dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
850dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
851dd1104fbSMichen Chang 			NUM_TO_STR(val, p->data.val_i);
852dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_INACTIVE, val);
853dd1104fbSMichen Chang 			break;
854dd1104fbSMichen Chang 
8557c478bd9Sstevel@tonic-gate 		case ATTR_EXPIRE:
856dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
857dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
858dd1104fbSMichen Chang 			NUM_TO_STR(val, p->data.val_i);
859dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_EXPIRE, val);
860dd1104fbSMichen Chang 			break;
861dd1104fbSMichen Chang 
8627c478bd9Sstevel@tonic-gate 		case ATTR_FLAG:
863dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled)
864dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
865dd1104fbSMichen Chang 			NUM_TO_STR(val, p->data.val_i);
866dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_FLAG, val);
867dd1104fbSMichen Chang 			break;
868dd1104fbSMichen Chang 		case ATTR_INCR_FAILED_LOGINS:
869dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled) {
870dd1104fbSMichen Chang 				rc = PWU_CHANGE_NOT_ALLOWED;
871dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
872dd1104fbSMichen Chang 			}
873dd1104fbSMichen Chang 			count = (spw->sp_flag & FAILCOUNT_MASK) + 1;
874dd1104fbSMichen Chang 			spw->sp_flag &= ~FAILCOUNT_MASK;
875dd1104fbSMichen Chang 			spw->sp_flag |= min(FAILCOUNT_MASK, count);
876dd1104fbSMichen Chang 			p->data.val_i = count;
877dd1104fbSMichen Chang 			NUM_TO_STR(val, spw->sp_flag);
878dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_FLAG, val);
879dd1104fbSMichen Chang 			break;
880dd1104fbSMichen Chang 		case ATTR_RST_FAILED_LOGINS:
881dd1104fbSMichen Chang 			if (!ldapbuf->shadow_update_enabled) {
882dd1104fbSMichen Chang 				rc = PWU_CHANGE_NOT_ALLOWED;
883dd1104fbSMichen Chang 				break;	/* not managing passwordAccount */
884dd1104fbSMichen Chang 			}
885dd1104fbSMichen Chang 			p->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
886dd1104fbSMichen Chang 			spw->sp_flag &= ~FAILCOUNT_MASK;
887dd1104fbSMichen Chang 			NUM_TO_STR(val, spw->sp_flag);
888dd1104fbSMichen Chang 			NEW_ATTR(sattrs, sidx, _S_FLAG, val);
8897c478bd9Sstevel@tonic-gate 			break;
8907c478bd9Sstevel@tonic-gate 		default:
8917c478bd9Sstevel@tonic-gate 			break;
8927c478bd9Sstevel@tonic-gate 		}
8937c478bd9Sstevel@tonic-gate 	}
8947c478bd9Sstevel@tonic-gate 
895dd1104fbSMichen Chang 	/*
896dd1104fbSMichen Chang 	 * If the ldap client is configured with shadow update enabled,
897dd1104fbSMichen Chang 	 * then what should the new aging values look like?
898dd1104fbSMichen Chang 	 *
899dd1104fbSMichen Chang 	 * There are a number of different conditions
900dd1104fbSMichen Chang 	 *
901dd1104fbSMichen Chang 	 *  a) aging is already configured: don't touch it
902dd1104fbSMichen Chang 	 *
903dd1104fbSMichen Chang 	 *  b) disable_aging is set: disable aging
904dd1104fbSMichen Chang 	 *
905dd1104fbSMichen Chang 	 *  c) aging is not configured: turn on default aging;
906dd1104fbSMichen Chang 	 *
907dd1104fbSMichen Chang 	 *  b) and c) of course only if aging_needed and !aging_set.
908dd1104fbSMichen Chang 	 *  (i.e., password changed, and aging values not changed)
909dd1104fbSMichen Chang 	 */
9107c478bd9Sstevel@tonic-gate 
911dd1104fbSMichen Chang 	if (ldapbuf->shadow_update_enabled && spw != NULL && spw->sp_max <= 0) {
912dd1104fbSMichen Chang 		/* a) aging not yet configured */
913dd1104fbSMichen Chang 		if (aging_needed && !aging_set) {
914dd1104fbSMichen Chang 			if (disable_aging) {
915dd1104fbSMichen Chang 				/* b) turn off aging */
916dd1104fbSMichen Chang 				spw->sp_min = spw->sp_max = spw->sp_warn = -1;
917dd1104fbSMichen Chang 				if (attr_addmod(sattrs, &sidx, _S_MIN, -1) < 0)
918dd1104fbSMichen Chang 					return (PWU_NOMEM);
919dd1104fbSMichen Chang 				if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0)
920dd1104fbSMichen Chang 					return (PWU_NOMEM);
921dd1104fbSMichen Chang 				if (attr_addmod(sattrs, &sidx, _S_WARNING,
922dd1104fbSMichen Chang 				    -1) < 0)
923dd1104fbSMichen Chang 					return (PWU_NOMEM);
924dd1104fbSMichen Chang 			} else {
925dd1104fbSMichen Chang 				/* c) */
926dd1104fbSMichen Chang 				turn_on_default_aging(spw);
927dd1104fbSMichen Chang 
928dd1104fbSMichen Chang 				if (attr_addmod(sattrs, &sidx, _S_MIN,
929dd1104fbSMichen Chang 				    spw->sp_min) < 0)
930dd1104fbSMichen Chang 					return (PWU_NOMEM);
931dd1104fbSMichen Chang 				if (attr_addmod(sattrs, &sidx, _S_MAX,
932dd1104fbSMichen Chang 				    spw->sp_max) < 0)
933dd1104fbSMichen Chang 					return (PWU_NOMEM);
934dd1104fbSMichen Chang 				if (attr_addmod(sattrs, &sidx,
935dd1104fbSMichen Chang 				    _S_WARNING, spw->sp_warn) < 0)
936dd1104fbSMichen Chang 					return (PWU_NOMEM);
937dd1104fbSMichen Chang 			}
938dd1104fbSMichen Chang 		}
939dd1104fbSMichen Chang 	}
940dd1104fbSMichen Chang 
941dd1104fbSMichen Chang 	pattrs[pidx] = NULL;
942dd1104fbSMichen Chang 	sattrs[sidx] = NULL;
943dd1104fbSMichen Chang 
944dd1104fbSMichen Chang 	return (rc);
9457c478bd9Sstevel@tonic-gate }
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate /*
9487c478bd9Sstevel@tonic-gate  * ldap_to_pwu_code(error, pwd_status)
9497c478bd9Sstevel@tonic-gate  *
9507c478bd9Sstevel@tonic-gate  * translation from LDAP return values and PWU return values
9517c478bd9Sstevel@tonic-gate  */
9527c478bd9Sstevel@tonic-gate int
ldap_to_pwu_code(int error,int pwd_status)9537c478bd9Sstevel@tonic-gate ldap_to_pwu_code(int error, int pwd_status)
9547c478bd9Sstevel@tonic-gate {
9557c478bd9Sstevel@tonic-gate 	switch (error) {
9567c478bd9Sstevel@tonic-gate 	case NS_LDAP_SUCCESS:	return (PWU_SUCCESS);
9577c478bd9Sstevel@tonic-gate 	case NS_LDAP_OP_FAILED:	return (PWU_DENIED);
9587c478bd9Sstevel@tonic-gate 	case NS_LDAP_NOTFOUND:	return (PWU_NOT_FOUND);
9597c478bd9Sstevel@tonic-gate 	case NS_LDAP_MEMORY:	return (PWU_NOMEM);
9607c478bd9Sstevel@tonic-gate 	case NS_LDAP_CONFIG:	return (PWU_NOT_FOUND);
9617c478bd9Sstevel@tonic-gate 	case NS_LDAP_INTERNAL:
9627c478bd9Sstevel@tonic-gate 		switch (pwd_status) {
9637c478bd9Sstevel@tonic-gate 		case NS_PASSWD_EXPIRED:
9647c478bd9Sstevel@tonic-gate 			return (PWU_DENIED);
9657c478bd9Sstevel@tonic-gate 		case NS_PASSWD_CHANGE_NOT_ALLOWED:
9667c478bd9Sstevel@tonic-gate 			return (PWU_CHANGE_NOT_ALLOWED);
9677c478bd9Sstevel@tonic-gate 		case NS_PASSWD_TOO_SHORT:
9687c478bd9Sstevel@tonic-gate 			return (PWU_PWD_TOO_SHORT);
9697c478bd9Sstevel@tonic-gate 		case NS_PASSWD_INVALID_SYNTAX:
9707c478bd9Sstevel@tonic-gate 			return (PWU_PWD_INVALID);
9717c478bd9Sstevel@tonic-gate 		case NS_PASSWD_IN_HISTORY:
9727c478bd9Sstevel@tonic-gate 			return (PWU_PWD_IN_HISTORY);
9737c478bd9Sstevel@tonic-gate 		case NS_PASSWD_WITHIN_MIN_AGE:
9747c478bd9Sstevel@tonic-gate 			return (PWU_WITHIN_MIN_AGE);
9757c478bd9Sstevel@tonic-gate 		default:
9767c478bd9Sstevel@tonic-gate 			return (PWU_SYSTEM_ERROR);
9777c478bd9Sstevel@tonic-gate 		}
9787c478bd9Sstevel@tonic-gate 	default:		return (PWU_SYSTEM_ERROR);
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate }
9817c478bd9Sstevel@tonic-gate 
9827c478bd9Sstevel@tonic-gate int
ldap_replaceattr(const char * dn,ns_ldap_attr_t ** attrs,const char * binddn,const char * pwd,int * pwd_status,int flags)9837c478bd9Sstevel@tonic-gate ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
984dd1104fbSMichen Chang 	const char *pwd, int *pwd_status, int flags)
9857c478bd9Sstevel@tonic-gate {
9867c478bd9Sstevel@tonic-gate 	int		result = NS_LDAP_OP_FAILED;
9877c478bd9Sstevel@tonic-gate 	int		ldaprc;
9887c478bd9Sstevel@tonic-gate 	int		authstried = 0;
9897c478bd9Sstevel@tonic-gate 	char		**certpath = NULL;
9907c478bd9Sstevel@tonic-gate 	ns_auth_t	**app;
9917c478bd9Sstevel@tonic-gate 	ns_auth_t	**authpp = NULL;
9927c478bd9Sstevel@tonic-gate 	ns_auth_t	*authp = NULL;
9937c478bd9Sstevel@tonic-gate 	ns_cred_t	*credp;
9947c478bd9Sstevel@tonic-gate 	ns_ldap_error_t	*errorp = NULL;
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	debug("%s: replace_ldapattr()", __FILE__);
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL)
999dd1104fbSMichen Chang 		return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */
10007c478bd9Sstevel@tonic-gate 
1001dd1104fbSMichen Chang 	/* for admin shadow update, dn and pwd will be set later in libsldap */
1002dd1104fbSMichen Chang 	if ((flags & NS_LDAP_UPDATE_SHADOW) == 0) {
10037c478bd9Sstevel@tonic-gate 		/* Fill in the user name and password */
10047c478bd9Sstevel@tonic-gate 		if (dn == NULL || pwd == NULL)
10057c478bd9Sstevel@tonic-gate 			goto out;
10067c478bd9Sstevel@tonic-gate 		credp->cred.unix_cred.userID = strdup(binddn);
10077c478bd9Sstevel@tonic-gate 		credp->cred.unix_cred.passwd = strdup(pwd);
1008dd1104fbSMichen Chang 	}
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate 	/* get host certificate path, if one is configured */
10117c478bd9Sstevel@tonic-gate 	ldaprc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
10127c478bd9Sstevel@tonic-gate 	    (void ***)&certpath, &errorp);
10137c478bd9Sstevel@tonic-gate 	if (ldaprc != NS_LDAP_SUCCESS)
10147c478bd9Sstevel@tonic-gate 		goto out;
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 	if (certpath && *certpath)
10177c478bd9Sstevel@tonic-gate 		credp->hostcertpath = *certpath;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	/* Load the service specific authentication method */
10207c478bd9Sstevel@tonic-gate 	ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
10217c478bd9Sstevel@tonic-gate 	    &errorp);
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 	if (ldaprc != NS_LDAP_SUCCESS)
10247c478bd9Sstevel@tonic-gate 		goto out;
10257c478bd9Sstevel@tonic-gate 
10267c478bd9Sstevel@tonic-gate 	/*
10277c478bd9Sstevel@tonic-gate 	 * if authpp is null, there is no serviceAuthenticationMethod
10287c478bd9Sstevel@tonic-gate 	 * try default authenticationMethod
10297c478bd9Sstevel@tonic-gate 	 */
10307c478bd9Sstevel@tonic-gate 	if (authpp == NULL) {
10317c478bd9Sstevel@tonic-gate 		ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
10327c478bd9Sstevel@tonic-gate 		    &errorp);
10337c478bd9Sstevel@tonic-gate 		if (ldaprc != NS_LDAP_SUCCESS)
10347c478bd9Sstevel@tonic-gate 			goto out;
10357c478bd9Sstevel@tonic-gate 	}
10367c478bd9Sstevel@tonic-gate 
10377c478bd9Sstevel@tonic-gate 	/*
10387c478bd9Sstevel@tonic-gate 	 * if authpp is still null, then can not authenticate, syslog
10397c478bd9Sstevel@tonic-gate 	 * error message and return error
10407c478bd9Sstevel@tonic-gate 	 */
10417c478bd9Sstevel@tonic-gate 	if (authpp == NULL) {
10427c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
10437c478bd9Sstevel@tonic-gate 		"passwdutil: no legal LDAP authentication method configured");
10447c478bd9Sstevel@tonic-gate 		result = NS_LDAP_OP_FAILED;
10457c478bd9Sstevel@tonic-gate 		goto out;
10467c478bd9Sstevel@tonic-gate 	}
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 	/*
10497c478bd9Sstevel@tonic-gate 	 * Walk the array and try all authentication methods in order except
10507c478bd9Sstevel@tonic-gate 	 * for "none".
10517c478bd9Sstevel@tonic-gate 	 */
10527c478bd9Sstevel@tonic-gate 	for (app = authpp; *app; app++) {
10537c478bd9Sstevel@tonic-gate 		authp = *app;
10547c478bd9Sstevel@tonic-gate 		/* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */
10557c478bd9Sstevel@tonic-gate 		if (authp->type == NS_LDAP_AUTH_NONE)
10567c478bd9Sstevel@tonic-gate 			continue;
10577c478bd9Sstevel@tonic-gate 		authstried++;
10587c478bd9Sstevel@tonic-gate 		credp->auth.type = authp->type;
10597c478bd9Sstevel@tonic-gate 		credp->auth.tlstype = authp->tlstype;
10607c478bd9Sstevel@tonic-gate 		credp->auth.saslmech = authp->saslmech;
10617c478bd9Sstevel@tonic-gate 		credp->auth.saslopt = authp->saslopt;
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 		ldaprc = __ns_ldap_repAttr("shadow", dn,
10647c478bd9Sstevel@tonic-gate 		    (const ns_ldap_attr_t * const *)attrs,
1065dd1104fbSMichen Chang 		    credp, flags, &errorp);
10667c478bd9Sstevel@tonic-gate 		if (ldaprc == NS_LDAP_SUCCESS) {
10677c478bd9Sstevel@tonic-gate 			result = NS_LDAP_SUCCESS;
10687c478bd9Sstevel@tonic-gate 			goto out;
10697c478bd9Sstevel@tonic-gate 		}
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 		/*
1072dd1104fbSMichen Chang 		 * if change not allowed due to configuration, indicate so
1073dd1104fbSMichen Chang 		 * to the caller
1074dd1104fbSMichen Chang 		 */
1075dd1104fbSMichen Chang 		if (ldaprc == NS_LDAP_CONFIG &&
1076dd1104fbSMichen Chang 		    errorp->status == NS_CONFIG_NOTALLOW) {
1077dd1104fbSMichen Chang 			result = NS_LDAP_CONFIG;
1078dd1104fbSMichen Chang 			*pwd_status = NS_PASSWD_CHANGE_NOT_ALLOWED;
1079dd1104fbSMichen Chang 			goto out;
1080dd1104fbSMichen Chang 		}
1081dd1104fbSMichen Chang 
1082dd1104fbSMichen Chang 		/*
10837c478bd9Sstevel@tonic-gate 		 * other errors might need to be added to this list, for
10847c478bd9Sstevel@tonic-gate 		 * the current supported mechanisms this is sufficient
10857c478bd9Sstevel@tonic-gate 		 */
10867c478bd9Sstevel@tonic-gate 		if ((ldaprc == NS_LDAP_INTERNAL) &&
10877c478bd9Sstevel@tonic-gate 		    (errorp->pwd_mgmt.status == NS_PASSWD_GOOD) &&
10887c478bd9Sstevel@tonic-gate 		    ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
10897c478bd9Sstevel@tonic-gate 		    (errorp->status == LDAP_INVALID_CREDENTIALS))) {
10907c478bd9Sstevel@tonic-gate 			result = ldaprc;
10917c478bd9Sstevel@tonic-gate 			goto out;
10927c478bd9Sstevel@tonic-gate 		}
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 		/*
10957c478bd9Sstevel@tonic-gate 		 * If there is error related to password policy,
10967c478bd9Sstevel@tonic-gate 		 * return it to caller
10977c478bd9Sstevel@tonic-gate 		 */
10987c478bd9Sstevel@tonic-gate 		if ((ldaprc == NS_LDAP_INTERNAL) &&
10997c478bd9Sstevel@tonic-gate 		    errorp->pwd_mgmt.status != NS_PASSWD_GOOD) {
11007c478bd9Sstevel@tonic-gate 			*pwd_status = errorp->pwd_mgmt.status;
11017c478bd9Sstevel@tonic-gate 			result = ldaprc;
11027c478bd9Sstevel@tonic-gate 			goto out;
11037c478bd9Sstevel@tonic-gate 		} else
11047c478bd9Sstevel@tonic-gate 			*pwd_status = NS_PASSWD_GOOD;
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 		/* we don't really care about the error, just clean it up */
11077c478bd9Sstevel@tonic-gate 		if (errorp)
11087c478bd9Sstevel@tonic-gate 			(void) __ns_ldap_freeError(&errorp);
11097c478bd9Sstevel@tonic-gate 	}
11107c478bd9Sstevel@tonic-gate 	if (authstried == 0) {
11117c478bd9Sstevel@tonic-gate 		syslog(LOG_ERR,
11127c478bd9Sstevel@tonic-gate 		"passwdutil: no legal LDAP authentication method configured");
11137c478bd9Sstevel@tonic-gate 		result = NS_LDAP_CONFIG;
11147c478bd9Sstevel@tonic-gate 		goto out;
11157c478bd9Sstevel@tonic-gate 	}
1116dd1104fbSMichen Chang 	result = NS_LDAP_OP_FAILED; /* map to PWU_DENIED */
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate out:
11197c478bd9Sstevel@tonic-gate 	if (credp)
11207c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeCred(&credp);
11217c478bd9Sstevel@tonic-gate 
11227c478bd9Sstevel@tonic-gate 	if (authpp)
11237c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeParam((void ***)&authpp);
11247c478bd9Sstevel@tonic-gate 
11257c478bd9Sstevel@tonic-gate 	if (errorp)
11267c478bd9Sstevel@tonic-gate 		(void) __ns_ldap_freeError(&errorp);
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 	return (result);
11297c478bd9Sstevel@tonic-gate }
11307c478bd9Sstevel@tonic-gate 
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate /*
113336e852a1SRaja Andra  * ldap_putpwnam(name, oldpw, rep, buf)
11347c478bd9Sstevel@tonic-gate  *
11357c478bd9Sstevel@tonic-gate  * update the LDAP server with the attributes contained in 'buf'.
11367c478bd9Sstevel@tonic-gate  */
11377c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11387c478bd9Sstevel@tonic-gate int
ldap_putpwnam(char * name,char * oldpw,pwu_repository_t * rep,void * buf)113936e852a1SRaja Andra ldap_putpwnam(char *name, char *oldpw, pwu_repository_t *rep, void *buf)
11407c478bd9Sstevel@tonic-gate {
11417c478bd9Sstevel@tonic-gate 	int res;
11427c478bd9Sstevel@tonic-gate 	char *dn;	/* dn of user whose attributes we are changing */
11437c478bd9Sstevel@tonic-gate 	char *binddn;	/* dn of user who is performing the change */
11447c478bd9Sstevel@tonic-gate 	ns_ldap_error_t *errorp;
11457c478bd9Sstevel@tonic-gate 	ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
1146dd1104fbSMichen Chang 	ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
1147dd1104fbSMichen Chang 	ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
11487c478bd9Sstevel@tonic-gate 	struct passwd *pw;
11497c478bd9Sstevel@tonic-gate 	int pwd_status;
11507c478bd9Sstevel@tonic-gate 	uid_t uid;
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	if (strcmp(name, "root") == 0)
11537c478bd9Sstevel@tonic-gate 		return (PWU_NOT_FOUND);
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	/*
1156dd1104fbSMichen Chang 	 * convert name of user whose attributes we are changing
1157dd1104fbSMichen Chang 	 * to a distinguished name
1158dd1104fbSMichen Chang 	 */
1159dd1104fbSMichen Chang 	res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
1160dd1104fbSMichen Chang 	if (res != NS_LDAP_SUCCESS)
1161dd1104fbSMichen Chang 		goto out;
1162dd1104fbSMichen Chang 
1163dd1104fbSMichen Chang 	/* update shadow via ldap_cachemgr if it is enabled */
1164dd1104fbSMichen Chang 	if (ldapbuf->shadow_update_enabled &&
1165dd1104fbSMichen Chang 	    sattrs != NULL && sattrs[0] != NULL) {
1166dd1104fbSMichen Chang 		/*
1167dd1104fbSMichen Chang 		 * flag NS_LDAP_UPDATE_SHADOW indicates the shadow update
1168dd1104fbSMichen Chang 		 * should be done via ldap_cachemgr
1169dd1104fbSMichen Chang 		 */
1170dd1104fbSMichen Chang 		res = ldap_replaceattr(dn, sattrs, NULL, NULL, &pwd_status,
1171dd1104fbSMichen Chang 		    NS_LDAP_UPDATE_SHADOW);
1172dd1104fbSMichen Chang 		goto out;
1173dd1104fbSMichen Chang 	}
1174dd1104fbSMichen Chang 
1175dd1104fbSMichen Chang 	/*
11767c478bd9Sstevel@tonic-gate 	 * The LDAP server checks whether we are permitted to perform
11777c478bd9Sstevel@tonic-gate 	 * the requested change. We need to send the name of the user
11787c478bd9Sstevel@tonic-gate 	 * who is executing this piece of code, together with his
11797c478bd9Sstevel@tonic-gate 	 * current password to the server.
11807c478bd9Sstevel@tonic-gate 	 * If this is executed by a normal user changing his/her own
11817c478bd9Sstevel@tonic-gate 	 * password, this will simply be the OLD password that is to
11827c478bd9Sstevel@tonic-gate 	 * be changed.
11837c478bd9Sstevel@tonic-gate 	 * Specific case if the user who is executing this piece
11847c478bd9Sstevel@tonic-gate 	 * of code is root. We will then issue the LDAP request
11857c478bd9Sstevel@tonic-gate 	 * with the DN of the user we want to change the passwd of.
11867c478bd9Sstevel@tonic-gate 	 */
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate 	/*
11897c478bd9Sstevel@tonic-gate 	 * create a dn for the user who is executing this code
11907c478bd9Sstevel@tonic-gate 	 */
11917c478bd9Sstevel@tonic-gate 	uid = getuid();
11927c478bd9Sstevel@tonic-gate 	if (uid == 0) {
11937c478bd9Sstevel@tonic-gate 		if ((pw = getpwnam_from(name, rep, REP_LDAP)) == NULL) {
11947c478bd9Sstevel@tonic-gate 			res = NS_LDAP_OP_FAILED;
11957c478bd9Sstevel@tonic-gate 			goto out;
11967c478bd9Sstevel@tonic-gate 		}
11977c478bd9Sstevel@tonic-gate 	} else if ((pw = getpwuid_from(uid, rep, REP_LDAP)) == NULL) {
11987c478bd9Sstevel@tonic-gate 		/*
11997c478bd9Sstevel@tonic-gate 		 * User executing this code is not known to the LDAP
12007c478bd9Sstevel@tonic-gate 		 * server. This operation is to be denied
12017c478bd9Sstevel@tonic-gate 		 */
12027c478bd9Sstevel@tonic-gate 		res = NS_LDAP_OP_FAILED;
12037c478bd9Sstevel@tonic-gate 		goto out;
12047c478bd9Sstevel@tonic-gate 	}
12057c478bd9Sstevel@tonic-gate 
12067c478bd9Sstevel@tonic-gate 	res = __ns_ldap_uid2dn(pw->pw_name, &binddn, NULL, &errorp);
12077c478bd9Sstevel@tonic-gate 	if (res != NS_LDAP_SUCCESS)
12087c478bd9Sstevel@tonic-gate 		goto out;
12097c478bd9Sstevel@tonic-gate 
1210dd1104fbSMichen Chang 	if (pattrs && pattrs[0] != NULL) {
1211dd1104fbSMichen Chang 		res = ldap_replaceattr(dn, pattrs, binddn, oldpw,
1212dd1104fbSMichen Chang 		    &pwd_status, 0);
1213dd1104fbSMichen Chang 	} else
1214dd1104fbSMichen Chang 		res = NS_LDAP_OP_FAILED;
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate out:
1217dd1104fbSMichen Chang 	free_ldapbuf(ldapbuf);
12187c478bd9Sstevel@tonic-gate 	free(dn);
12197c478bd9Sstevel@tonic-gate 
12207c478bd9Sstevel@tonic-gate 	return (ldap_to_pwu_code(res, pwd_status));
12217c478bd9Sstevel@tonic-gate }
1222