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.
25*cbea7acaSDominik Hassler * Copyright 2024 OmniOS Community Edition (OmniOSce) Association.
267c478bd9Sstevel@tonic-gate */
277c478bd9Sstevel@tonic-gate
287c478bd9Sstevel@tonic-gate #include <stdio.h>
297c478bd9Sstevel@tonic-gate #include <errno.h>
307c478bd9Sstevel@tonic-gate #include <stdlib.h>
317c478bd9Sstevel@tonic-gate #include <string.h>
327c478bd9Sstevel@tonic-gate #include <unistd.h>
33dd1104fbSMichen Chang #include <macros.h>
34dd1104fbSMichen Chang #include <priv.h>
357c478bd9Sstevel@tonic-gate
367c478bd9Sstevel@tonic-gate #include "ns_sldap.h"
377c478bd9Sstevel@tonic-gate
387c478bd9Sstevel@tonic-gate #include <nss_dbdefs.h>
397c478bd9Sstevel@tonic-gate #include <nsswitch.h>
407c478bd9Sstevel@tonic-gate
417c478bd9Sstevel@tonic-gate #include <pwd.h>
427c478bd9Sstevel@tonic-gate #include <shadow.h>
437c478bd9Sstevel@tonic-gate #include <syslog.h>
447c478bd9Sstevel@tonic-gate
457c478bd9Sstevel@tonic-gate #include "passwdutil.h"
467c478bd9Sstevel@tonic-gate
477c478bd9Sstevel@tonic-gate #include "utils.h"
487c478bd9Sstevel@tonic-gate
49dd1104fbSMichen Chang #define MAX_INT_LEN 11 /* 10+1 %d buflen for words/ints [not longs] */
50dd1104fbSMichen Chang
51dd1104fbSMichen Chang #define STRDUP_OR_RET(to, from) \
52dd1104fbSMichen Chang if ((to = strdup(from)) == NULL) \
53dd1104fbSMichen Chang return (PWU_NOMEM);
54dd1104fbSMichen Chang
55dd1104fbSMichen Chang #define STRDUP_OR_ERR(to, from, err) \
56dd1104fbSMichen Chang if (((to) = strdup(from)) == NULL) \
57dd1104fbSMichen Chang (err) = PWU_NOMEM;
58dd1104fbSMichen Chang
59dd1104fbSMichen Chang #define NUM_TO_STR(to, from) \
60dd1104fbSMichen Chang { \
61dd1104fbSMichen Chang char nb[MAX_INT_LEN]; \
62dd1104fbSMichen Chang if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \
63dd1104fbSMichen Chang return (PWU_NOMEM); \
64dd1104fbSMichen Chang STRDUP_OR_RET(to, nb); \
65dd1104fbSMichen Chang }
66dd1104fbSMichen Chang
67dd1104fbSMichen Chang #define NEW_ATTR(p, i, attr, val) \
68dd1104fbSMichen Chang { \
69dd1104fbSMichen Chang p[i] = new_attr(attr, (val)); \
70dd1104fbSMichen Chang if (p[i] == NULL) \
71dd1104fbSMichen Chang return (PWU_NOMEM); \
72dd1104fbSMichen Chang i++; \
73dd1104fbSMichen Chang }
74dd1104fbSMichen Chang
75*cbea7acaSDominik Hassler int ldap_getattr(const char *name, attrlist *item, pwu_repository_t *rep);
76*cbea7acaSDominik Hassler int ldap_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep,
777c478bd9Sstevel@tonic-gate void **buf);
787c478bd9Sstevel@tonic-gate int ldap_update(attrlist *items, pwu_repository_t *rep, void *buf);
79*cbea7acaSDominik Hassler int ldap_putpwnam(const char *name, const char *oldpw, pwu_repository_t *rep,
80*cbea7acaSDominik Hassler void *buf);
81*cbea7acaSDominik Hassler int ldap_user_to_authenticate(const char *name, pwu_repository_t *rep,
827c478bd9Sstevel@tonic-gate char **auth_user, int *privileged);
837c478bd9Sstevel@tonic-gate
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate * ldap function pointer table, used by passwdutil_init to initialize
867c478bd9Sstevel@tonic-gate * the global Repository-OPerations table "rops"
877c478bd9Sstevel@tonic-gate */
887c478bd9Sstevel@tonic-gate struct repops ldap_repops = {
897c478bd9Sstevel@tonic-gate NULL, /* checkhistory */
907c478bd9Sstevel@tonic-gate ldap_getattr,
917c478bd9Sstevel@tonic-gate ldap_getpwnam,
927c478bd9Sstevel@tonic-gate ldap_update,
937c478bd9Sstevel@tonic-gate ldap_putpwnam,
947c478bd9Sstevel@tonic-gate ldap_user_to_authenticate,
957c478bd9Sstevel@tonic-gate NULL, /* lock */
967c478bd9Sstevel@tonic-gate NULL /* unlock */
977c478bd9Sstevel@tonic-gate };
987c478bd9Sstevel@tonic-gate
997c478bd9Sstevel@tonic-gate /*
1007c478bd9Sstevel@tonic-gate * structure used to keep state between get/update/put calls
1017c478bd9Sstevel@tonic-gate */
1027c478bd9Sstevel@tonic-gate typedef struct {
1037c478bd9Sstevel@tonic-gate char *passwd; /* encrypted password */
1047c478bd9Sstevel@tonic-gate struct passwd *pwd;
105dd1104fbSMichen Chang ns_ldap_attr_t **pattrs; /* passwd attrs */
106dd1104fbSMichen Chang int npattrs; /* max attrs */
107dd1104fbSMichen Chang struct spwd *spwd;
108dd1104fbSMichen Chang ns_ldap_attr_t **sattrs; /* passwd attrs */
109dd1104fbSMichen Chang int nsattrs; /* max attrs */
110dd1104fbSMichen Chang boolean_t shadow_update_enabled; /* shadow update configured */
1117c478bd9Sstevel@tonic-gate } ldapbuf_t;
1127c478bd9Sstevel@tonic-gate
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate * The following define's are taken from
1157c478bd9Sstevel@tonic-gate * usr/src/lib/nsswitch/ldap/common/getpwnam.c
1167c478bd9Sstevel@tonic-gate */
1177c478bd9Sstevel@tonic-gate
1187c478bd9Sstevel@tonic-gate /* passwd attributes filters */
1197c478bd9Sstevel@tonic-gate #define _PWD_CN "cn"
1207c478bd9Sstevel@tonic-gate #define _PWD_UID "uid"
1217c478bd9Sstevel@tonic-gate #define _PWD_USERPASSWORD "userpassword"
1227c478bd9Sstevel@tonic-gate #define _PWD_UIDNUMBER "uidnumber"
1237c478bd9Sstevel@tonic-gate #define _PWD_GIDNUMBER "gidnumber"
1247c478bd9Sstevel@tonic-gate #define _PWD_GECOS "gecos"
1257c478bd9Sstevel@tonic-gate #define _PWD_DESCRIPTION "description"
1267c478bd9Sstevel@tonic-gate #define _PWD_HOMEDIRECTORY "homedirectory"
1277c478bd9Sstevel@tonic-gate #define _PWD_LOGINSHELL "loginshell"
1287c478bd9Sstevel@tonic-gate
129dd1104fbSMichen Chang #define _PWD_MAX_ATTR 10 /* 9+NULL */
130dd1104fbSMichen Chang
131dd1104fbSMichen Chang /* shadow attributes filters */
132dd1104fbSMichen Chang #define _S_LASTCHANGE "shadowlastchange"
133dd1104fbSMichen Chang #define _S_MIN "shadowmin"
134dd1104fbSMichen Chang #define _S_MAX "shadowmax"
135dd1104fbSMichen Chang #define _S_WARNING "shadowwarning"
136dd1104fbSMichen Chang #define _S_INACTIVE "shadowinactive"
137dd1104fbSMichen Chang #define _S_EXPIRE "shadowexpire"
138dd1104fbSMichen Chang #define _S_FLAG "shadowflag"
139dd1104fbSMichen Chang
140dd1104fbSMichen Chang #define _S_MAX_ATTR 8 /* 7+NULL */
141dd1104fbSMichen Chang
142dd1104fbSMichen Chang /*
143dd1104fbSMichen Chang * Frees up an ldapbuf_t
144dd1104fbSMichen Chang */
145dd1104fbSMichen Chang
146dd1104fbSMichen Chang static void
free_ldapbuf(ldapbuf_t * p)147dd1104fbSMichen Chang free_ldapbuf(ldapbuf_t *p)
148dd1104fbSMichen Chang {
149dd1104fbSMichen Chang int i;
150dd1104fbSMichen Chang
151dd1104fbSMichen Chang if (p == NULL)
152dd1104fbSMichen Chang return;
153dd1104fbSMichen Chang if (p->passwd) {
154dd1104fbSMichen Chang (void) memset(p->passwd, 0, strlen(p->passwd));
155dd1104fbSMichen Chang free(p->passwd);
156dd1104fbSMichen Chang }
157dd1104fbSMichen Chang if (p->pwd)
158dd1104fbSMichen Chang free_pwd(p->pwd);
159dd1104fbSMichen Chang if (p->spwd)
160dd1104fbSMichen Chang free_spwd(p->spwd);
161dd1104fbSMichen Chang if (p->pattrs) {
162dd1104fbSMichen Chang for (i = 0; i < p->npattrs; i++) {
163dd1104fbSMichen Chang if (p->pattrs[i] != NULL) {
164dd1104fbSMichen Chang free(p->pattrs[i]->attrvalue[0]);
165dd1104fbSMichen Chang free(p->pattrs[i]);
166dd1104fbSMichen Chang }
167dd1104fbSMichen Chang }
168dd1104fbSMichen Chang free(p->pattrs);
169dd1104fbSMichen Chang }
170dd1104fbSMichen Chang if (p->sattrs) {
171dd1104fbSMichen Chang for (i = 0; i < p->nsattrs; i++) {
172dd1104fbSMichen Chang if (p->sattrs[i] != NULL) {
173dd1104fbSMichen Chang free(p->sattrs[i]->attrvalue[0]);
174dd1104fbSMichen Chang free(p->sattrs[i]);
175dd1104fbSMichen Chang }
176dd1104fbSMichen Chang }
177dd1104fbSMichen Chang free(p->sattrs);
178dd1104fbSMichen Chang }
179dd1104fbSMichen Chang }
180dd1104fbSMichen Chang
1817c478bd9Sstevel@tonic-gate /*
1827c478bd9Sstevel@tonic-gate * int ldap_user_to_authenticate(user, rep, auth_user, privileged)
1837c478bd9Sstevel@tonic-gate *
184dd1104fbSMichen Chang * If the Shadow Update functionality is enabled, then we check to
185dd1104fbSMichen Chang * see if the caller has 0 as the euid or has all zone privs. If so,
186bbf21555SRichard Lowe * the caller would be able to modify shadow(5) data stored on the
187dd1104fbSMichen Chang * LDAP server. Otherwise, when LDAP Shadow Update is not enabled,
188dd1104fbSMichen Chang * we can't determine whether the user is "privileged" in the LDAP
189dd1104fbSMichen Chang * sense. The operation should be attempted and will succeed if the
190dd1104fbSMichen Chang * user had privileges. For our purposes, we say that the user is
19148bbca81SDaniel Hoffman * privileged if they are attempting to change another user's
192dd1104fbSMichen Chang * password attributes.
1937c478bd9Sstevel@tonic-gate */
1947c478bd9Sstevel@tonic-gate int
ldap_user_to_authenticate(const char * user,pwu_repository_t * rep,char ** auth_user,int * privileged)195*cbea7acaSDominik Hassler ldap_user_to_authenticate(const char *user, pwu_repository_t *rep,
1967c478bd9Sstevel@tonic-gate char **auth_user, int *privileged)
1977c478bd9Sstevel@tonic-gate {
1987c478bd9Sstevel@tonic-gate struct passwd *pw;
1997c478bd9Sstevel@tonic-gate uid_t uid;
2007c478bd9Sstevel@tonic-gate uid_t priviledged_uid;
2017c478bd9Sstevel@tonic-gate int res = PWU_SUCCESS;
2027c478bd9Sstevel@tonic-gate
2037c478bd9Sstevel@tonic-gate if (strcmp(user, "root") == 0)
2047c478bd9Sstevel@tonic-gate return (PWU_NOT_FOUND);
2057c478bd9Sstevel@tonic-gate
2067c478bd9Sstevel@tonic-gate if ((pw = getpwnam_from(user, rep, REP_LDAP)) == NULL)
2077c478bd9Sstevel@tonic-gate return (PWU_NOT_FOUND);
2087c478bd9Sstevel@tonic-gate
2097c478bd9Sstevel@tonic-gate uid = getuid();
2107c478bd9Sstevel@tonic-gate
211dd1104fbSMichen Chang /*
212dd1104fbSMichen Chang * need equivalent of write access to /etc/shadow
213dd1104fbSMichen Chang * the privilege escalation model is euid == 0 || all zone privs
214dd1104fbSMichen Chang */
215dd1104fbSMichen Chang if (__ns_ldap_is_shadow_update_enabled()) {
216dd1104fbSMichen Chang boolean_t priv;
217dd1104fbSMichen Chang
218dd1104fbSMichen Chang priv = (geteuid() == 0);
219dd1104fbSMichen Chang if (!priv) {
220dd1104fbSMichen Chang priv_set_t *ps = priv_allocset(); /* caller */
221dd1104fbSMichen Chang priv_set_t *zs; /* zone */
222dd1104fbSMichen Chang
223dd1104fbSMichen Chang (void) getppriv(PRIV_EFFECTIVE, ps);
224dd1104fbSMichen Chang zs = priv_str_to_set("zone", ",", NULL);
225dd1104fbSMichen Chang priv = priv_isequalset(ps, zs);
226dd1104fbSMichen Chang priv_freeset(ps);
227dd1104fbSMichen Chang priv_freeset(zs);
228dd1104fbSMichen Chang }
229dd1104fbSMichen Chang /*
230dd1104fbSMichen Chang * priv can change anyone's password,
231dd1104fbSMichen Chang * only root isn't prompted.
232dd1104fbSMichen Chang */
233dd1104fbSMichen Chang *privileged = 0; /* for proper prompting */
234dd1104fbSMichen Chang if (priv) {
235dd1104fbSMichen Chang if (uid == 0) {
236dd1104fbSMichen Chang *privileged = 1;
237dd1104fbSMichen Chang *auth_user = NULL;
238dd1104fbSMichen Chang return (res);
239dd1104fbSMichen Chang } else if (uid == pw->pw_uid) {
240dd1104fbSMichen Chang STRDUP_OR_ERR(*auth_user, user, res);
241dd1104fbSMichen Chang return (res);
242dd1104fbSMichen Chang }
243dd1104fbSMichen Chang }
244dd1104fbSMichen Chang
245dd1104fbSMichen Chang return (PWU_DENIED);
246dd1104fbSMichen Chang }
247dd1104fbSMichen Chang
2487c478bd9Sstevel@tonic-gate if (uid == pw->pw_uid) {
249dd1104fbSMichen Chang /* changing our own, not privileged */
2507c478bd9Sstevel@tonic-gate *privileged = 0;
251dd1104fbSMichen Chang STRDUP_OR_RET(*auth_user, user);
2527c478bd9Sstevel@tonic-gate } else {
2537c478bd9Sstevel@tonic-gate char pwd_buf[1024];
2547c478bd9Sstevel@tonic-gate struct passwd pwr;
2557c478bd9Sstevel@tonic-gate
2567c478bd9Sstevel@tonic-gate *privileged = 1;
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate * specific case for root
2597c478bd9Sstevel@tonic-gate * we want 'user' to be authenticated.
2607c478bd9Sstevel@tonic-gate */
2617c478bd9Sstevel@tonic-gate if (uid == 0) {
2627c478bd9Sstevel@tonic-gate priviledged_uid = pw->pw_uid;
2637c478bd9Sstevel@tonic-gate } else {
2647c478bd9Sstevel@tonic-gate priviledged_uid = uid;
2657c478bd9Sstevel@tonic-gate }
2667c478bd9Sstevel@tonic-gate if (getpwuid_r(priviledged_uid, &pwr, pwd_buf,
2677c478bd9Sstevel@tonic-gate sizeof (pwd_buf)) != NULL) {
268dd1104fbSMichen Chang STRDUP_OR_ERR(*auth_user, pwr.pw_name, res);
2697c478bd9Sstevel@tonic-gate } else {
2707c478bd9Sstevel@tonic-gate /* hmm. can't find name of current user...??? */
2717c478bd9Sstevel@tonic-gate
272dd1104fbSMichen Chang if ((*auth_user = malloc(MAX_INT_LEN)) == NULL) {
2737c478bd9Sstevel@tonic-gate res = PWU_NOMEM;
2747c478bd9Sstevel@tonic-gate } else {
275dd1104fbSMichen Chang (void) snprintf(*auth_user, MAX_INT_LEN, "%d",
2767c478bd9Sstevel@tonic-gate (int)uid);
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate }
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate
2817c478bd9Sstevel@tonic-gate return (res);
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate
2847c478bd9Sstevel@tonic-gate /*
2857c478bd9Sstevel@tonic-gate * int ldap_getattr(name, item, rep)
2867c478bd9Sstevel@tonic-gate *
2877c478bd9Sstevel@tonic-gate * retrieve attributes specified in "item" for user "name".
2887c478bd9Sstevel@tonic-gate */
2897c478bd9Sstevel@tonic-gate /*ARGSUSED*/
2907c478bd9Sstevel@tonic-gate int
ldap_getattr(const char * name,attrlist * items,pwu_repository_t * rep)291*cbea7acaSDominik Hassler ldap_getattr(const char *name, attrlist *items, pwu_repository_t *rep)
2927c478bd9Sstevel@tonic-gate {
293dd1104fbSMichen Chang attrlist *w;
2947c478bd9Sstevel@tonic-gate int res;
295dd1104fbSMichen Chang ldapbuf_t *ldapbuf;
2967c478bd9Sstevel@tonic-gate struct passwd *pw = NULL;
2977c478bd9Sstevel@tonic-gate struct spwd *spw = NULL;
2987c478bd9Sstevel@tonic-gate
299dd1104fbSMichen Chang res = ldap_getpwnam(name, items, rep, (void **)&ldapbuf);
3007c478bd9Sstevel@tonic-gate if (res != PWU_SUCCESS)
301dd1104fbSMichen Chang return (res);
3027c478bd9Sstevel@tonic-gate
303dd1104fbSMichen Chang pw = ldapbuf->pwd;
304dd1104fbSMichen Chang spw = ldapbuf->spwd;
3057c478bd9Sstevel@tonic-gate
3067c478bd9Sstevel@tonic-gate for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) {
3077c478bd9Sstevel@tonic-gate switch (w->type) {
3087c478bd9Sstevel@tonic-gate case ATTR_NAME:
309dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_name, res);
3107c478bd9Sstevel@tonic-gate break;
3117c478bd9Sstevel@tonic-gate case ATTR_COMMENT:
312dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_comment, res);
3137c478bd9Sstevel@tonic-gate break;
3147c478bd9Sstevel@tonic-gate case ATTR_GECOS:
315dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_gecos, res);
3167c478bd9Sstevel@tonic-gate break;
3177c478bd9Sstevel@tonic-gate case ATTR_HOMEDIR:
318dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_dir, res);
3197c478bd9Sstevel@tonic-gate break;
3207c478bd9Sstevel@tonic-gate case ATTR_SHELL:
321dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_shell, res);
3227c478bd9Sstevel@tonic-gate break;
3237c478bd9Sstevel@tonic-gate case ATTR_PASSWD:
3247c478bd9Sstevel@tonic-gate case ATTR_PASSWD_SERVER_POLICY:
325dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, spw->sp_pwdp, res);
3267c478bd9Sstevel@tonic-gate break;
3277c478bd9Sstevel@tonic-gate case ATTR_AGE:
328dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_age, res);
3297c478bd9Sstevel@tonic-gate break;
3307c478bd9Sstevel@tonic-gate case ATTR_REP_NAME:
331dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, "ldap", res);
3327c478bd9Sstevel@tonic-gate break;
3337c478bd9Sstevel@tonic-gate
3347c478bd9Sstevel@tonic-gate /* integer values */
3357c478bd9Sstevel@tonic-gate case ATTR_UID:
3367c478bd9Sstevel@tonic-gate w->data.val_i = pw->pw_uid;
3377c478bd9Sstevel@tonic-gate break;
3387c478bd9Sstevel@tonic-gate case ATTR_GID:
3397c478bd9Sstevel@tonic-gate w->data.val_i = pw->pw_gid;
3407c478bd9Sstevel@tonic-gate break;
3417c478bd9Sstevel@tonic-gate case ATTR_LSTCHG:
342dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled)
343dd1104fbSMichen Chang w->data.val_i = spw->sp_lstchg;
344dd1104fbSMichen Chang else
3457c478bd9Sstevel@tonic-gate w->data.val_i = -1;
3467c478bd9Sstevel@tonic-gate break;
3477c478bd9Sstevel@tonic-gate case ATTR_MIN:
348dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled)
349dd1104fbSMichen Chang w->data.val_i = spw->sp_min;
350dd1104fbSMichen Chang else
3517c478bd9Sstevel@tonic-gate w->data.val_i = -1;
3527c478bd9Sstevel@tonic-gate break;
3537c478bd9Sstevel@tonic-gate case ATTR_MAX:
354dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled)
355dd1104fbSMichen Chang w->data.val_i = spw->sp_max;
356dd1104fbSMichen Chang else
3577c478bd9Sstevel@tonic-gate w->data.val_i = -1;
3587c478bd9Sstevel@tonic-gate break;
3597c478bd9Sstevel@tonic-gate case ATTR_WARN:
360dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled)
361dd1104fbSMichen Chang w->data.val_i = spw->sp_warn;
362dd1104fbSMichen Chang else
3637c478bd9Sstevel@tonic-gate w->data.val_i = -1;
3647c478bd9Sstevel@tonic-gate break;
3657c478bd9Sstevel@tonic-gate case ATTR_INACT:
366dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled)
367dd1104fbSMichen Chang w->data.val_i = spw->sp_inact;
368dd1104fbSMichen Chang else
3697c478bd9Sstevel@tonic-gate w->data.val_i = -1;
3707c478bd9Sstevel@tonic-gate break;
3717c478bd9Sstevel@tonic-gate case ATTR_EXPIRE:
372dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled)
373dd1104fbSMichen Chang w->data.val_i = spw->sp_expire;
374dd1104fbSMichen Chang else
3757c478bd9Sstevel@tonic-gate w->data.val_i = -1;
3767c478bd9Sstevel@tonic-gate break;
3777c478bd9Sstevel@tonic-gate case ATTR_FLAG:
378dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled)
379dd1104fbSMichen Chang w->data.val_i = spw->sp_flag;
380dd1104fbSMichen Chang break;
381dd1104fbSMichen Chang case ATTR_FAILED_LOGINS:
382dd1104fbSMichen Chang w->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
3837c478bd9Sstevel@tonic-gate break;
3847c478bd9Sstevel@tonic-gate default:
3857c478bd9Sstevel@tonic-gate break;
3867c478bd9Sstevel@tonic-gate }
3877c478bd9Sstevel@tonic-gate }
3887c478bd9Sstevel@tonic-gate
3897c478bd9Sstevel@tonic-gate out:
390dd1104fbSMichen Chang free_ldapbuf(ldapbuf);
391dd1104fbSMichen Chang free(ldapbuf);
3927c478bd9Sstevel@tonic-gate return (res);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate * int ldap_getpwnam(name, items, rep, buf)
3977c478bd9Sstevel@tonic-gate *
3987c478bd9Sstevel@tonic-gate * There is no need to get the old values from the ldap
3997c478bd9Sstevel@tonic-gate * server, as the update will update each item individually.
4007c478bd9Sstevel@tonic-gate * Therefore, we only allocate a buffer that will be used by
4017c478bd9Sstevel@tonic-gate * _update and _putpwnam to hold the attributes to update.
4027c478bd9Sstevel@tonic-gate *
4037c478bd9Sstevel@tonic-gate * Only when we're about to update a password, we need to retrieve
4047c478bd9Sstevel@tonic-gate * the old password since it contains salt-information.
4057c478bd9Sstevel@tonic-gate */
4067c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4077c478bd9Sstevel@tonic-gate int
ldap_getpwnam(const char * name,attrlist * items,pwu_repository_t * rep,void ** buf)408*cbea7acaSDominik Hassler ldap_getpwnam(const char *name, attrlist *items, pwu_repository_t *rep,
4097c478bd9Sstevel@tonic-gate void **buf)
4107c478bd9Sstevel@tonic-gate {
4117c478bd9Sstevel@tonic-gate ldapbuf_t *ldapbuf;
412dd1104fbSMichen Chang int res = PWU_NOMEM;
4137c478bd9Sstevel@tonic-gate
414dd1104fbSMichen Chang /*
415dd1104fbSMichen Chang * [sp]attrs is treated as NULL terminated
416dd1104fbSMichen Chang */
4177c478bd9Sstevel@tonic-gate
4187c478bd9Sstevel@tonic-gate ldapbuf = calloc(1, sizeof (ldapbuf_t));
4197c478bd9Sstevel@tonic-gate if (ldapbuf == NULL)
4207c478bd9Sstevel@tonic-gate return (PWU_NOMEM);
4217c478bd9Sstevel@tonic-gate
422dd1104fbSMichen Chang ldapbuf->pattrs = calloc(_PWD_MAX_ATTR, sizeof (ns_ldap_attr_t *));
423dd1104fbSMichen Chang if (ldapbuf->pattrs == NULL)
424dd1104fbSMichen Chang goto out;
425dd1104fbSMichen Chang ldapbuf->npattrs = _PWD_MAX_ATTR;
4267c478bd9Sstevel@tonic-gate
427dd1104fbSMichen Chang ldapbuf->sattrs = calloc(_S_MAX_ATTR, sizeof (ns_ldap_attr_t *));
428dd1104fbSMichen Chang if (ldapbuf->sattrs == NULL)
429dd1104fbSMichen Chang goto out;
430dd1104fbSMichen Chang ldapbuf->nsattrs = _S_MAX_ATTR;
4317c478bd9Sstevel@tonic-gate
4327c478bd9Sstevel@tonic-gate res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP));
4337c478bd9Sstevel@tonic-gate if (res != PWU_SUCCESS)
434dd1104fbSMichen Chang goto out;
4357c478bd9Sstevel@tonic-gate
436dd1104fbSMichen Chang res = dup_spw(&ldapbuf->spwd, getspnam_from(name, rep, REP_LDAP));
437dd1104fbSMichen Chang if (res != PWU_SUCCESS)
438dd1104fbSMichen Chang goto out;
439dd1104fbSMichen Chang else {
440dd1104fbSMichen Chang char *spw = ldapbuf->spwd->sp_pwdp;
441dd1104fbSMichen Chang if (spw != NULL && *spw != '\0') {
442dd1104fbSMichen Chang ldapbuf->passwd = strdup(spw);
4437c478bd9Sstevel@tonic-gate if (ldapbuf->passwd == NULL)
444dd1104fbSMichen Chang goto out;
445dd1104fbSMichen Chang } else
446dd1104fbSMichen Chang ldapbuf->passwd = NULL;
4477c478bd9Sstevel@tonic-gate }
4487c478bd9Sstevel@tonic-gate
449dd1104fbSMichen Chang /* remember if shadow update is enabled */
450dd1104fbSMichen Chang ldapbuf->shadow_update_enabled = __ns_ldap_is_shadow_update_enabled();
451dd1104fbSMichen Chang
452dd1104fbSMichen Chang *buf = (void *)ldapbuf;
453dd1104fbSMichen Chang return (PWU_SUCCESS);
454dd1104fbSMichen Chang
455dd1104fbSMichen Chang out:
456dd1104fbSMichen Chang free_ldapbuf(ldapbuf);
457dd1104fbSMichen Chang free(ldapbuf);
458dd1104fbSMichen Chang return (res);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate
4617c478bd9Sstevel@tonic-gate /*
4627c478bd9Sstevel@tonic-gate * new_attr(name, value)
4637c478bd9Sstevel@tonic-gate *
4647c478bd9Sstevel@tonic-gate * create a new LDAP attribute to be sent to the server
4657c478bd9Sstevel@tonic-gate */
4667c478bd9Sstevel@tonic-gate ns_ldap_attr_t *
new_attr(char * name,char * value)4677c478bd9Sstevel@tonic-gate new_attr(char *name, char *value)
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate ns_ldap_attr_t *tmp;
4707c478bd9Sstevel@tonic-gate
4717c478bd9Sstevel@tonic-gate tmp = malloc(sizeof (*tmp));
4727c478bd9Sstevel@tonic-gate if (tmp != NULL) {
4737c478bd9Sstevel@tonic-gate tmp->attrname = name;
4747c478bd9Sstevel@tonic-gate tmp->attrvalue = (char **)calloc(2, sizeof (char *));
4757c478bd9Sstevel@tonic-gate if (tmp->attrvalue == NULL) {
4767c478bd9Sstevel@tonic-gate free(tmp);
4777c478bd9Sstevel@tonic-gate return (NULL);
4787c478bd9Sstevel@tonic-gate }
4797c478bd9Sstevel@tonic-gate tmp->attrvalue[0] = value;
4807c478bd9Sstevel@tonic-gate tmp->value_count = 1;
4817c478bd9Sstevel@tonic-gate }
4827c478bd9Sstevel@tonic-gate
4837c478bd9Sstevel@tonic-gate return (tmp);
4847c478bd9Sstevel@tonic-gate }
4857c478bd9Sstevel@tonic-gate
4867c478bd9Sstevel@tonic-gate /*
487dd1104fbSMichen Chang * max_present(list)
488dd1104fbSMichen Chang *
489dd1104fbSMichen Chang * returns '1' if a ATTR_MAX with value != -1 is present. (in other words:
490dd1104fbSMichen Chang * if password aging is to be turned on).
491dd1104fbSMichen Chang */
492dd1104fbSMichen Chang static int
max_present(attrlist * list)493dd1104fbSMichen Chang max_present(attrlist *list)
494dd1104fbSMichen Chang {
495dd1104fbSMichen Chang while (list != NULL)
496dd1104fbSMichen Chang if (list->type == ATTR_MAX && list->data.val_i != -1)
497dd1104fbSMichen Chang return (1);
498dd1104fbSMichen Chang else
499dd1104fbSMichen Chang list = list->next;
500dd1104fbSMichen Chang return (0);
501dd1104fbSMichen Chang }
502dd1104fbSMichen Chang
503dd1104fbSMichen Chang /*
504dd1104fbSMichen Chang * attr_addmod(attrs, idx, item, val)
505dd1104fbSMichen Chang *
506dd1104fbSMichen Chang * Adds or updates attribute 'item' in ldap_attrs list to value
507dd1104fbSMichen Chang * update idx if item is added
508dd1104fbSMichen Chang * return: -1 - PWU_NOMEM/error, 0 - success
509dd1104fbSMichen Chang */
510dd1104fbSMichen Chang static int
attr_addmod(ns_ldap_attr_t ** attrs,int * idx,char * item,int value)511dd1104fbSMichen Chang attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value)
512dd1104fbSMichen Chang {
513dd1104fbSMichen Chang char numbuf[MAX_INT_LEN], *strp;
514dd1104fbSMichen Chang int i;
515dd1104fbSMichen Chang
516dd1104fbSMichen Chang /* stringize the value or abort */
517dd1104fbSMichen Chang if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN)
518dd1104fbSMichen Chang return (-1);
519dd1104fbSMichen Chang
520dd1104fbSMichen Chang /* check for existence and modify existing */
521dd1104fbSMichen Chang for (i = 0; i < *idx; i++) {
522dd1104fbSMichen Chang if (attrs[i] != NULL &&
523dd1104fbSMichen Chang strcmp(item, attrs[i]->attrname) == 0) {
524dd1104fbSMichen Chang strp = strdup(numbuf);
525dd1104fbSMichen Chang if (strp == NULL)
526dd1104fbSMichen Chang return (-1);
527dd1104fbSMichen Chang free(attrs[i]->attrvalue[0]);
528dd1104fbSMichen Chang attrs[i]->attrvalue[0] = strp;
529dd1104fbSMichen Chang return (0);
530dd1104fbSMichen Chang }
531dd1104fbSMichen Chang }
532dd1104fbSMichen Chang /* else add */
533dd1104fbSMichen Chang strp = strdup(numbuf);
534dd1104fbSMichen Chang if (strp == NULL)
535dd1104fbSMichen Chang return (-1);
536dd1104fbSMichen Chang attrs[*idx] = new_attr(item, strp);
537dd1104fbSMichen Chang if (attrs[*idx] == NULL)
538dd1104fbSMichen Chang return (-1);
539dd1104fbSMichen Chang (*idx)++;
540dd1104fbSMichen Chang return (0);
541dd1104fbSMichen Chang }
542dd1104fbSMichen Chang
543dd1104fbSMichen Chang /*
5447c478bd9Sstevel@tonic-gate * ldap_update(items, rep, buf)
5457c478bd9Sstevel@tonic-gate *
5467c478bd9Sstevel@tonic-gate * create LDAP attributes in 'buf' for each attribute in 'items'.
5477c478bd9Sstevel@tonic-gate */
5487c478bd9Sstevel@tonic-gate /*ARGSUSED*/
5497c478bd9Sstevel@tonic-gate int
ldap_update(attrlist * items,pwu_repository_t * rep,void * buf)5507c478bd9Sstevel@tonic-gate ldap_update(attrlist *items, pwu_repository_t *rep, void *buf)
5517c478bd9Sstevel@tonic-gate {
5527c478bd9Sstevel@tonic-gate attrlist *p;
5537c478bd9Sstevel@tonic-gate ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
554dd1104fbSMichen Chang struct spwd *spw;
555dd1104fbSMichen Chang ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
556dd1104fbSMichen Chang int pidx = 0;
557dd1104fbSMichen Chang ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
558dd1104fbSMichen Chang int sidx = 0;
5597c478bd9Sstevel@tonic-gate char *pwd, *val;
5607c478bd9Sstevel@tonic-gate char *salt;
5617c478bd9Sstevel@tonic-gate size_t cryptlen;
562dd1104fbSMichen Chang int len;
563dd1104fbSMichen Chang int count;
564dd1104fbSMichen Chang int rc = PWU_SUCCESS;
565dd1104fbSMichen Chang int aging_needed = 0;
566dd1104fbSMichen Chang int aging_set = 0;
567dd1104fbSMichen Chang int disable_aging;
568dd1104fbSMichen Chang
569dd1104fbSMichen Chang spw = ldapbuf->spwd;
570dd1104fbSMichen Chang
571dd1104fbSMichen Chang /*
572dd1104fbSMichen Chang * if sp_max==0 and shadow update is enabled:
573dd1104fbSMichen Chang * disable passwd aging after updating the password
574dd1104fbSMichen Chang */
575dd1104fbSMichen Chang disable_aging = (spw != NULL && spw->sp_max == 0 &&
576dd1104fbSMichen Chang ldapbuf->shadow_update_enabled);
5777c478bd9Sstevel@tonic-gate
5787c478bd9Sstevel@tonic-gate for (p = items; p != NULL; p = p->next) {
5797c478bd9Sstevel@tonic-gate switch (p->type) {
5807c478bd9Sstevel@tonic-gate case ATTR_PASSWD:
581dd1104fbSMichen Chang /*
582dd1104fbSMichen Chang * There is a special case for ldap: if the
583dd1104fbSMichen Chang * password is to be deleted (-d to passwd),
584dd1104fbSMichen Chang * p->data.val_s will be NULL.
585dd1104fbSMichen Chang */
586dd1104fbSMichen Chang if (p->data.val_s == NULL) {
587dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
588dd1104fbSMichen Chang return (PWU_CHANGE_NOT_ALLOWED);
589dd1104fbSMichen Chang cryptlen =
590dd1104fbSMichen Chang sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
591dd1104fbSMichen Chang val = malloc(cryptlen);
592dd1104fbSMichen Chang if (val == NULL)
593dd1104fbSMichen Chang return (PWU_NOMEM);
594dd1104fbSMichen Chang (void) snprintf(val, cryptlen,
595dd1104fbSMichen Chang "{crypt}" NS_LDAP_NO_UNIX_PASSWORD);
596dd1104fbSMichen Chang } else { /* not deleting password */
597dd1104fbSMichen Chang salt = crypt_gensalt(ldapbuf->passwd,
598dd1104fbSMichen Chang ldapbuf->pwd);
5997c478bd9Sstevel@tonic-gate
6007c478bd9Sstevel@tonic-gate if (salt == NULL) {
6017c478bd9Sstevel@tonic-gate if (errno == ENOMEM)
6027c478bd9Sstevel@tonic-gate return (PWU_NOMEM);
603dd1104fbSMichen Chang
6047c478bd9Sstevel@tonic-gate /* algorithm problem? */
6057c478bd9Sstevel@tonic-gate syslog(LOG_AUTH | LOG_ALERT,
6067c478bd9Sstevel@tonic-gate "passwdutil: crypt_gensalt "
6077c478bd9Sstevel@tonic-gate "%m");
6087c478bd9Sstevel@tonic-gate return (PWU_UPDATE_FAILED);
6097c478bd9Sstevel@tonic-gate }
6107c478bd9Sstevel@tonic-gate
6117c478bd9Sstevel@tonic-gate pwd = crypt(p->data.val_s, salt);
6127c478bd9Sstevel@tonic-gate free(salt);
6137c478bd9Sstevel@tonic-gate cryptlen = strlen(pwd) + sizeof ("{crypt}");
6147c478bd9Sstevel@tonic-gate val = malloc(cryptlen);
6157c478bd9Sstevel@tonic-gate if (val == NULL)
6167c478bd9Sstevel@tonic-gate return (PWU_NOMEM);
617dd1104fbSMichen Chang (void) snprintf(val, cryptlen,
618dd1104fbSMichen Chang "{crypt}%s", pwd);
619dd1104fbSMichen Chang }
6207c478bd9Sstevel@tonic-gate
621dd1104fbSMichen Chang /*
622dd1104fbSMichen Chang * If not managing passwordAccount,
623dd1104fbSMichen Chang * insert the new password in the
624dd1104fbSMichen Chang * passwd attr array and break.
625dd1104fbSMichen Chang */
626dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) {
627dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx,
628dd1104fbSMichen Chang _PWD_USERPASSWORD, val);
6297c478bd9Sstevel@tonic-gate break;
630dd1104fbSMichen Chang }
631dd1104fbSMichen Chang
632dd1104fbSMichen Chang /*
633dd1104fbSMichen Chang * Managing passwordAccount, insert the
634dd1104fbSMichen Chang * new password, along with lastChange and
635dd1104fbSMichen Chang * shadowFlag, in the shadow attr array.
636dd1104fbSMichen Chang */
637dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, val);
638dd1104fbSMichen Chang
639dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
640dd1104fbSMichen Chang DAY_NOW_32) < 0)
641dd1104fbSMichen Chang return (PWU_NOMEM);
642dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32;
643dd1104fbSMichen Chang
644dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_FLAG,
645dd1104fbSMichen Chang spw->sp_flag & ~FAILCOUNT_MASK) < 0)
646dd1104fbSMichen Chang return (PWU_NOMEM);
647dd1104fbSMichen Chang spw->sp_flag &= ~FAILCOUNT_MASK; /* reset count */
648dd1104fbSMichen Chang aging_needed = 1;
649dd1104fbSMichen Chang break;
650dd1104fbSMichen Chang case ATTR_PASSWD_SERVER_POLICY:
6517c478bd9Sstevel@tonic-gate /*
6527c478bd9Sstevel@tonic-gate * For server policy, don't crypt the password,
6537c478bd9Sstevel@tonic-gate * send the password as is to the server and
6547c478bd9Sstevel@tonic-gate * let the LDAP server do its own password
6557c478bd9Sstevel@tonic-gate * encryption
6567c478bd9Sstevel@tonic-gate */
657dd1104fbSMichen Chang STRDUP_OR_RET(val, p->data.val_s);
6587c478bd9Sstevel@tonic-gate
659dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_USERPASSWORD, val);
6607c478bd9Sstevel@tonic-gate break;
6617c478bd9Sstevel@tonic-gate case ATTR_COMMENT:
6627c478bd9Sstevel@tonic-gate /* XX correct? */
663dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_DESCRIPTION, p->data.val_s);
6647c478bd9Sstevel@tonic-gate break;
6657c478bd9Sstevel@tonic-gate case ATTR_GECOS:
666dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) {
667dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_GECOS,
668dd1104fbSMichen Chang p->data.val_s);
669dd1104fbSMichen Chang } else {
670dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_GECOS,
671dd1104fbSMichen Chang p->data.val_s);
672dd1104fbSMichen Chang }
6737c478bd9Sstevel@tonic-gate break;
6747c478bd9Sstevel@tonic-gate case ATTR_HOMEDIR:
675dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) {
676dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_HOMEDIRECTORY,
6777c478bd9Sstevel@tonic-gate p->data.val_s);
678dd1104fbSMichen Chang } else {
679dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_HOMEDIRECTORY,
680dd1104fbSMichen Chang p->data.val_s);
681dd1104fbSMichen Chang }
6827c478bd9Sstevel@tonic-gate break;
6837c478bd9Sstevel@tonic-gate case ATTR_SHELL:
684dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) {
685dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_LOGINSHELL,
686dd1104fbSMichen Chang p->data.val_s);
687dd1104fbSMichen Chang } else {
688dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_LOGINSHELL,
689dd1104fbSMichen Chang p->data.val_s);
690dd1104fbSMichen Chang }
6917c478bd9Sstevel@tonic-gate break;
692dd1104fbSMichen Chang /* We don't update NAME, UID, GID */
6937c478bd9Sstevel@tonic-gate case ATTR_NAME:
6947c478bd9Sstevel@tonic-gate case ATTR_UID:
6957c478bd9Sstevel@tonic-gate case ATTR_GID:
696dd1104fbSMichen Chang /* Unsupported item */
6977c478bd9Sstevel@tonic-gate case ATTR_AGE:
698dd1104fbSMichen Chang break;
699dd1104fbSMichen Chang case ATTR_LOCK_ACCOUNT:
700dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
701dd1104fbSMichen Chang break; /* not managing passwordAccount */
702dd1104fbSMichen Chang if (spw->sp_pwdp == NULL) {
703dd1104fbSMichen Chang spw->sp_pwdp = LOCKSTRING;
7045477a4d9Sgww } else if ((strncmp(spw->sp_pwdp, LOCKSTRING,
7055477a4d9Sgww sizeof (LOCKSTRING)-1) != 0) &&
7065477a4d9Sgww (strcmp(spw->sp_pwdp, NOLOGINSTRING) != 0)) {
707dd1104fbSMichen Chang len = sizeof (LOCKSTRING)-1 +
708dd1104fbSMichen Chang strlen(spw->sp_pwdp) + 1 +
709dd1104fbSMichen Chang sizeof ("{crypt}");
710dd1104fbSMichen Chang pwd = malloc(len);
711dd1104fbSMichen Chang if (pwd == NULL) {
712dd1104fbSMichen Chang return (PWU_NOMEM);
713dd1104fbSMichen Chang }
714dd1104fbSMichen Chang (void) strlcpy(pwd, "{crypt}", len);
715dd1104fbSMichen Chang (void) strlcat(pwd, LOCKSTRING, len);
716dd1104fbSMichen Chang (void) strlcat(pwd, spw->sp_pwdp, len);
717dd1104fbSMichen Chang free(spw->sp_pwdp);
718dd1104fbSMichen Chang spw->sp_pwdp = pwd;
719dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
720dd1104fbSMichen Chang spw->sp_pwdp);
721dd1104fbSMichen Chang }
722dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
723dd1104fbSMichen Chang DAY_NOW_32) < 0)
724dd1104fbSMichen Chang return (PWU_NOMEM);
725dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32;
726dd1104fbSMichen Chang break;
727dd1104fbSMichen Chang
728dd1104fbSMichen Chang case ATTR_UNLOCK_ACCOUNT:
729dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
730dd1104fbSMichen Chang break; /* not managing passwordAccount */
731dd1104fbSMichen Chang if (spw->sp_pwdp &&
732dd1104fbSMichen Chang strncmp(spw->sp_pwdp, LOCKSTRING,
733dd1104fbSMichen Chang sizeof (LOCKSTRING)-1) == 0) {
734dd1104fbSMichen Chang len = (sizeof ("{crypt}") -
735dd1104fbSMichen Chang sizeof (LOCKSTRING)) +
736dd1104fbSMichen Chang strlen(spw->sp_pwdp) + 1;
737dd1104fbSMichen Chang pwd = malloc(len);
738dd1104fbSMichen Chang if (pwd == NULL) {
739dd1104fbSMichen Chang return (PWU_NOMEM);
740dd1104fbSMichen Chang }
741dd1104fbSMichen Chang (void) strlcpy(pwd, "{crypt}", len);
742dd1104fbSMichen Chang (void) strlcat(pwd, spw->sp_pwdp +
743dd1104fbSMichen Chang sizeof (LOCKSTRING)-1, len);
744dd1104fbSMichen Chang free(spw->sp_pwdp);
745dd1104fbSMichen Chang spw->sp_pwdp = pwd;
746dd1104fbSMichen Chang
747dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD,
748dd1104fbSMichen Chang spw->sp_pwdp);
749dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
750dd1104fbSMichen Chang DAY_NOW_32) < 0)
751dd1104fbSMichen Chang return (PWU_NOMEM);
752dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32;
753dd1104fbSMichen Chang }
754dd1104fbSMichen Chang break;
755dd1104fbSMichen Chang
756dd1104fbSMichen Chang case ATTR_NOLOGIN_ACCOUNT:
757dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
758dd1104fbSMichen Chang break; /* not managing passwordAccount */
759dd1104fbSMichen Chang free(spw->sp_pwdp);
760dd1104fbSMichen Chang STRDUP_OR_RET(spw->sp_pwdp, "{crypt}" NOLOGINSTRING);
761dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, spw->sp_pwdp);
762dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE,
763dd1104fbSMichen Chang DAY_NOW_32) < 0)
764dd1104fbSMichen Chang return (PWU_NOMEM);
765dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32;
766dd1104fbSMichen Chang break;
767dd1104fbSMichen Chang
768dd1104fbSMichen Chang case ATTR_EXPIRE_PASSWORD:
769dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
770dd1104fbSMichen Chang break; /* not managing passwordAccount */
771dd1104fbSMichen Chang NUM_TO_STR(val, 0);
772dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
773dd1104fbSMichen Chang break;
774dd1104fbSMichen Chang
7757c478bd9Sstevel@tonic-gate case ATTR_LSTCHG:
776dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
777dd1104fbSMichen Chang break; /* not managing passwordAccount */
778dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i);
779dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val);
780dd1104fbSMichen Chang break;
781dd1104fbSMichen Chang
7827c478bd9Sstevel@tonic-gate case ATTR_MIN:
783dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
784dd1104fbSMichen Chang break; /* not managing passwordAccount */
785dd1104fbSMichen Chang if (spw->sp_max == -1 && p->data.val_i != -1 &&
786dd1104fbSMichen Chang max_present(p->next) == 0)
787dd1104fbSMichen Chang return (PWU_AGING_DISABLED);
788dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i);
789dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_MIN, val);
790dd1104fbSMichen Chang aging_set = 1;
791dd1104fbSMichen Chang break;
792dd1104fbSMichen Chang
7937c478bd9Sstevel@tonic-gate case ATTR_MAX:
794dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
795dd1104fbSMichen Chang break; /* not managing passwordAccount */
796dd1104fbSMichen Chang if (p->data.val_i == -1) {
797dd1104fbSMichen Chang /* Turn off aging. Reset min and warn too */
798dd1104fbSMichen Chang spw->sp_max = spw->sp_min = spw->sp_warn = -1;
799dd1104fbSMichen Chang NUM_TO_STR(val, -1);
800dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_MIN, val);
801dd1104fbSMichen Chang NUM_TO_STR(val, -1);
802dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_WARNING, val);
803dd1104fbSMichen Chang } else {
804dd1104fbSMichen Chang /* Turn account aging on */
805dd1104fbSMichen Chang if (spw->sp_min == -1) {
806dd1104fbSMichen Chang /*
807dd1104fbSMichen Chang * minage was not set with command-
808dd1104fbSMichen Chang * line option: set to zero
809dd1104fbSMichen Chang */
810dd1104fbSMichen Chang spw->sp_min = 0;
811dd1104fbSMichen Chang NUM_TO_STR(val, 0);
812dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_MIN,
813dd1104fbSMichen Chang val);
814dd1104fbSMichen Chang }
815dd1104fbSMichen Chang /*
816dd1104fbSMichen Chang * If aging was turned off, we update lstchg.
817dd1104fbSMichen Chang * We take care not to update lstchg if the
818dd1104fbSMichen Chang * user has no password, otherwise the user
819dd1104fbSMichen Chang * might not be required to provide a password
82048bbca81SDaniel Hoffman * the next time they log in.
821dd1104fbSMichen Chang *
822dd1104fbSMichen Chang * Also, if lstchg != -1 (i.e., not set)
823dd1104fbSMichen Chang * we keep the old value.
824dd1104fbSMichen Chang */
825dd1104fbSMichen Chang if (spw->sp_max == -1 &&
826dd1104fbSMichen Chang spw->sp_pwdp != NULL && *spw->sp_pwdp &&
827dd1104fbSMichen Chang spw->sp_lstchg == -1) {
828dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx,
829dd1104fbSMichen Chang _S_LASTCHANGE,
830dd1104fbSMichen Chang DAY_NOW_32) < 0)
831dd1104fbSMichen Chang return (PWU_NOMEM);
832dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32;
833dd1104fbSMichen Chang }
834dd1104fbSMichen Chang }
835dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i);
836dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_MAX, val);
837dd1104fbSMichen Chang aging_set = 1;
838dd1104fbSMichen Chang break;
839dd1104fbSMichen Chang
8407c478bd9Sstevel@tonic-gate case ATTR_WARN:
841dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
842dd1104fbSMichen Chang break; /* not managing passwordAccount */
843dd1104fbSMichen Chang if (spw->sp_max == -1 &&
844dd1104fbSMichen Chang p->data.val_i != -1 && max_present(p->next) == 0)
845dd1104fbSMichen Chang return (PWU_AGING_DISABLED);
846dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i);
847dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_WARNING, val);
848dd1104fbSMichen Chang break;
849dd1104fbSMichen Chang
8507c478bd9Sstevel@tonic-gate case ATTR_INACT:
851dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
852dd1104fbSMichen Chang break; /* not managing passwordAccount */
853dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i);
854dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_INACTIVE, val);
855dd1104fbSMichen Chang break;
856dd1104fbSMichen Chang
8577c478bd9Sstevel@tonic-gate case ATTR_EXPIRE:
858dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
859dd1104fbSMichen Chang break; /* not managing passwordAccount */
860dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i);
861dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_EXPIRE, val);
862dd1104fbSMichen Chang break;
863dd1104fbSMichen Chang
8647c478bd9Sstevel@tonic-gate case ATTR_FLAG:
865dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled)
866dd1104fbSMichen Chang break; /* not managing passwordAccount */
867dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i);
868dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_FLAG, val);
869dd1104fbSMichen Chang break;
870dd1104fbSMichen Chang case ATTR_INCR_FAILED_LOGINS:
871dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) {
872dd1104fbSMichen Chang rc = PWU_CHANGE_NOT_ALLOWED;
873dd1104fbSMichen Chang break; /* not managing passwordAccount */
874dd1104fbSMichen Chang }
875dd1104fbSMichen Chang count = (spw->sp_flag & FAILCOUNT_MASK) + 1;
876dd1104fbSMichen Chang spw->sp_flag &= ~FAILCOUNT_MASK;
877dd1104fbSMichen Chang spw->sp_flag |= min(FAILCOUNT_MASK, count);
878dd1104fbSMichen Chang p->data.val_i = count;
879dd1104fbSMichen Chang NUM_TO_STR(val, spw->sp_flag);
880dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_FLAG, val);
881dd1104fbSMichen Chang break;
882dd1104fbSMichen Chang case ATTR_RST_FAILED_LOGINS:
883dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) {
884dd1104fbSMichen Chang rc = PWU_CHANGE_NOT_ALLOWED;
885dd1104fbSMichen Chang break; /* not managing passwordAccount */
886dd1104fbSMichen Chang }
887dd1104fbSMichen Chang p->data.val_i = spw->sp_flag & FAILCOUNT_MASK;
888dd1104fbSMichen Chang spw->sp_flag &= ~FAILCOUNT_MASK;
889dd1104fbSMichen Chang NUM_TO_STR(val, spw->sp_flag);
890dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_FLAG, val);
8917c478bd9Sstevel@tonic-gate break;
8927c478bd9Sstevel@tonic-gate default:
8937c478bd9Sstevel@tonic-gate break;
8947c478bd9Sstevel@tonic-gate }
8957c478bd9Sstevel@tonic-gate }
8967c478bd9Sstevel@tonic-gate
897dd1104fbSMichen Chang /*
898dd1104fbSMichen Chang * If the ldap client is configured with shadow update enabled,
899dd1104fbSMichen Chang * then what should the new aging values look like?
900dd1104fbSMichen Chang *
901dd1104fbSMichen Chang * There are a number of different conditions
902dd1104fbSMichen Chang *
903dd1104fbSMichen Chang * a) aging is already configured: don't touch it
904dd1104fbSMichen Chang *
905dd1104fbSMichen Chang * b) disable_aging is set: disable aging
906dd1104fbSMichen Chang *
907dd1104fbSMichen Chang * c) aging is not configured: turn on default aging;
908dd1104fbSMichen Chang *
909dd1104fbSMichen Chang * b) and c) of course only if aging_needed and !aging_set.
910dd1104fbSMichen Chang * (i.e., password changed, and aging values not changed)
911dd1104fbSMichen Chang */
9127c478bd9Sstevel@tonic-gate
913dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled && spw != NULL && spw->sp_max <= 0) {
914dd1104fbSMichen Chang /* a) aging not yet configured */
915dd1104fbSMichen Chang if (aging_needed && !aging_set) {
916dd1104fbSMichen Chang if (disable_aging) {
917dd1104fbSMichen Chang /* b) turn off aging */
918dd1104fbSMichen Chang spw->sp_min = spw->sp_max = spw->sp_warn = -1;
919dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_MIN, -1) < 0)
920dd1104fbSMichen Chang return (PWU_NOMEM);
921dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0)
922dd1104fbSMichen Chang return (PWU_NOMEM);
923dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_WARNING,
924dd1104fbSMichen Chang -1) < 0)
925dd1104fbSMichen Chang return (PWU_NOMEM);
926dd1104fbSMichen Chang } else {
927dd1104fbSMichen Chang /* c) */
928dd1104fbSMichen Chang turn_on_default_aging(spw);
929dd1104fbSMichen Chang
930dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_MIN,
931dd1104fbSMichen Chang spw->sp_min) < 0)
932dd1104fbSMichen Chang return (PWU_NOMEM);
933dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_MAX,
934dd1104fbSMichen Chang spw->sp_max) < 0)
935dd1104fbSMichen Chang return (PWU_NOMEM);
936dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx,
937dd1104fbSMichen Chang _S_WARNING, spw->sp_warn) < 0)
938dd1104fbSMichen Chang return (PWU_NOMEM);
939dd1104fbSMichen Chang }
940dd1104fbSMichen Chang }
941dd1104fbSMichen Chang }
942dd1104fbSMichen Chang
943dd1104fbSMichen Chang pattrs[pidx] = NULL;
944dd1104fbSMichen Chang sattrs[sidx] = NULL;
945dd1104fbSMichen Chang
946dd1104fbSMichen Chang return (rc);
9477c478bd9Sstevel@tonic-gate }
9487c478bd9Sstevel@tonic-gate
9497c478bd9Sstevel@tonic-gate /*
9507c478bd9Sstevel@tonic-gate * ldap_to_pwu_code(error, pwd_status)
9517c478bd9Sstevel@tonic-gate *
9527c478bd9Sstevel@tonic-gate * translation from LDAP return values and PWU return values
9537c478bd9Sstevel@tonic-gate */
9547c478bd9Sstevel@tonic-gate int
ldap_to_pwu_code(int error,int pwd_status)9557c478bd9Sstevel@tonic-gate ldap_to_pwu_code(int error, int pwd_status)
9567c478bd9Sstevel@tonic-gate {
9577c478bd9Sstevel@tonic-gate switch (error) {
9587c478bd9Sstevel@tonic-gate case NS_LDAP_SUCCESS: return (PWU_SUCCESS);
9597c478bd9Sstevel@tonic-gate case NS_LDAP_OP_FAILED: return (PWU_DENIED);
9607c478bd9Sstevel@tonic-gate case NS_LDAP_NOTFOUND: return (PWU_NOT_FOUND);
9617c478bd9Sstevel@tonic-gate case NS_LDAP_MEMORY: return (PWU_NOMEM);
9627c478bd9Sstevel@tonic-gate case NS_LDAP_CONFIG: return (PWU_NOT_FOUND);
9637c478bd9Sstevel@tonic-gate case NS_LDAP_INTERNAL:
9647c478bd9Sstevel@tonic-gate switch (pwd_status) {
9657c478bd9Sstevel@tonic-gate case NS_PASSWD_EXPIRED:
9667c478bd9Sstevel@tonic-gate return (PWU_DENIED);
9677c478bd9Sstevel@tonic-gate case NS_PASSWD_CHANGE_NOT_ALLOWED:
9687c478bd9Sstevel@tonic-gate return (PWU_CHANGE_NOT_ALLOWED);
9697c478bd9Sstevel@tonic-gate case NS_PASSWD_TOO_SHORT:
9707c478bd9Sstevel@tonic-gate return (PWU_PWD_TOO_SHORT);
9717c478bd9Sstevel@tonic-gate case NS_PASSWD_INVALID_SYNTAX:
9727c478bd9Sstevel@tonic-gate return (PWU_PWD_INVALID);
9737c478bd9Sstevel@tonic-gate case NS_PASSWD_IN_HISTORY:
9747c478bd9Sstevel@tonic-gate return (PWU_PWD_IN_HISTORY);
9757c478bd9Sstevel@tonic-gate case NS_PASSWD_WITHIN_MIN_AGE:
9767c478bd9Sstevel@tonic-gate return (PWU_WITHIN_MIN_AGE);
9777c478bd9Sstevel@tonic-gate default:
9787c478bd9Sstevel@tonic-gate return (PWU_SYSTEM_ERROR);
9797c478bd9Sstevel@tonic-gate }
9807c478bd9Sstevel@tonic-gate default: return (PWU_SYSTEM_ERROR);
9817c478bd9Sstevel@tonic-gate }
9827c478bd9Sstevel@tonic-gate }
9837c478bd9Sstevel@tonic-gate
9847c478bd9Sstevel@tonic-gate int
ldap_replaceattr(const char * dn,ns_ldap_attr_t ** attrs,const char * binddn,const char * pwd,int * pwd_status,int flags)9857c478bd9Sstevel@tonic-gate ldap_replaceattr(const char *dn, ns_ldap_attr_t **attrs, const char *binddn,
986dd1104fbSMichen Chang const char *pwd, int *pwd_status, int flags)
9877c478bd9Sstevel@tonic-gate {
9887c478bd9Sstevel@tonic-gate int result = NS_LDAP_OP_FAILED;
9897c478bd9Sstevel@tonic-gate int ldaprc;
9907c478bd9Sstevel@tonic-gate int authstried = 0;
9917c478bd9Sstevel@tonic-gate char **certpath = NULL;
9927c478bd9Sstevel@tonic-gate ns_auth_t **app;
9937c478bd9Sstevel@tonic-gate ns_auth_t **authpp = NULL;
9947c478bd9Sstevel@tonic-gate ns_auth_t *authp = NULL;
9957c478bd9Sstevel@tonic-gate ns_cred_t *credp;
9967c478bd9Sstevel@tonic-gate ns_ldap_error_t *errorp = NULL;
9977c478bd9Sstevel@tonic-gate
9987c478bd9Sstevel@tonic-gate debug("%s: replace_ldapattr()", __FILE__);
9997c478bd9Sstevel@tonic-gate
10007c478bd9Sstevel@tonic-gate if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL)
1001dd1104fbSMichen Chang return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */
10027c478bd9Sstevel@tonic-gate
1003dd1104fbSMichen Chang /* for admin shadow update, dn and pwd will be set later in libsldap */
1004dd1104fbSMichen Chang if ((flags & NS_LDAP_UPDATE_SHADOW) == 0) {
10057c478bd9Sstevel@tonic-gate /* Fill in the user name and password */
10067c478bd9Sstevel@tonic-gate if (dn == NULL || pwd == NULL)
10077c478bd9Sstevel@tonic-gate goto out;
10087c478bd9Sstevel@tonic-gate credp->cred.unix_cred.userID = strdup(binddn);
10097c478bd9Sstevel@tonic-gate credp->cred.unix_cred.passwd = strdup(pwd);
1010dd1104fbSMichen Chang }
10117c478bd9Sstevel@tonic-gate
10127c478bd9Sstevel@tonic-gate /* get host certificate path, if one is configured */
10137c478bd9Sstevel@tonic-gate ldaprc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P,
10147c478bd9Sstevel@tonic-gate (void ***)&certpath, &errorp);
10157c478bd9Sstevel@tonic-gate if (ldaprc != NS_LDAP_SUCCESS)
10167c478bd9Sstevel@tonic-gate goto out;
10177c478bd9Sstevel@tonic-gate
10187c478bd9Sstevel@tonic-gate if (certpath && *certpath)
10197c478bd9Sstevel@tonic-gate credp->hostcertpath = *certpath;
10207c478bd9Sstevel@tonic-gate
10217c478bd9Sstevel@tonic-gate /* Load the service specific authentication method */
10227c478bd9Sstevel@tonic-gate ldaprc = __ns_ldap_getServiceAuthMethods("passwd-cmd", &authpp,
10237c478bd9Sstevel@tonic-gate &errorp);
10247c478bd9Sstevel@tonic-gate
10257c478bd9Sstevel@tonic-gate if (ldaprc != NS_LDAP_SUCCESS)
10267c478bd9Sstevel@tonic-gate goto out;
10277c478bd9Sstevel@tonic-gate
10287c478bd9Sstevel@tonic-gate /*
10297c478bd9Sstevel@tonic-gate * if authpp is null, there is no serviceAuthenticationMethod
10307c478bd9Sstevel@tonic-gate * try default authenticationMethod
10317c478bd9Sstevel@tonic-gate */
10327c478bd9Sstevel@tonic-gate if (authpp == NULL) {
10337c478bd9Sstevel@tonic-gate ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp,
10347c478bd9Sstevel@tonic-gate &errorp);
10357c478bd9Sstevel@tonic-gate if (ldaprc != NS_LDAP_SUCCESS)
10367c478bd9Sstevel@tonic-gate goto out;
10377c478bd9Sstevel@tonic-gate }
10387c478bd9Sstevel@tonic-gate
10397c478bd9Sstevel@tonic-gate /*
10407c478bd9Sstevel@tonic-gate * if authpp is still null, then can not authenticate, syslog
10417c478bd9Sstevel@tonic-gate * error message and return error
10427c478bd9Sstevel@tonic-gate */
10437c478bd9Sstevel@tonic-gate if (authpp == NULL) {
10447c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
10457c478bd9Sstevel@tonic-gate "passwdutil: no legal LDAP authentication method configured");
10467c478bd9Sstevel@tonic-gate result = NS_LDAP_OP_FAILED;
10477c478bd9Sstevel@tonic-gate goto out;
10487c478bd9Sstevel@tonic-gate }
10497c478bd9Sstevel@tonic-gate
10507c478bd9Sstevel@tonic-gate /*
10517c478bd9Sstevel@tonic-gate * Walk the array and try all authentication methods in order except
10527c478bd9Sstevel@tonic-gate * for "none".
10537c478bd9Sstevel@tonic-gate */
10547c478bd9Sstevel@tonic-gate for (app = authpp; *app; app++) {
10557c478bd9Sstevel@tonic-gate authp = *app;
10567c478bd9Sstevel@tonic-gate /* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */
10577c478bd9Sstevel@tonic-gate if (authp->type == NS_LDAP_AUTH_NONE)
10587c478bd9Sstevel@tonic-gate continue;
10597c478bd9Sstevel@tonic-gate authstried++;
10607c478bd9Sstevel@tonic-gate credp->auth.type = authp->type;
10617c478bd9Sstevel@tonic-gate credp->auth.tlstype = authp->tlstype;
10627c478bd9Sstevel@tonic-gate credp->auth.saslmech = authp->saslmech;
10637c478bd9Sstevel@tonic-gate credp->auth.saslopt = authp->saslopt;
10647c478bd9Sstevel@tonic-gate
10657c478bd9Sstevel@tonic-gate ldaprc = __ns_ldap_repAttr("shadow", dn,
10667c478bd9Sstevel@tonic-gate (const ns_ldap_attr_t * const *)attrs,
1067dd1104fbSMichen Chang credp, flags, &errorp);
10687c478bd9Sstevel@tonic-gate if (ldaprc == NS_LDAP_SUCCESS) {
10697c478bd9Sstevel@tonic-gate result = NS_LDAP_SUCCESS;
10707c478bd9Sstevel@tonic-gate goto out;
10717c478bd9Sstevel@tonic-gate }
10727c478bd9Sstevel@tonic-gate
10737c478bd9Sstevel@tonic-gate /*
1074dd1104fbSMichen Chang * if change not allowed due to configuration, indicate so
1075dd1104fbSMichen Chang * to the caller
1076dd1104fbSMichen Chang */
1077dd1104fbSMichen Chang if (ldaprc == NS_LDAP_CONFIG &&
1078dd1104fbSMichen Chang errorp->status == NS_CONFIG_NOTALLOW) {
1079dd1104fbSMichen Chang result = NS_LDAP_CONFIG;
1080dd1104fbSMichen Chang *pwd_status = NS_PASSWD_CHANGE_NOT_ALLOWED;
1081dd1104fbSMichen Chang goto out;
1082dd1104fbSMichen Chang }
1083dd1104fbSMichen Chang
1084dd1104fbSMichen Chang /*
10857c478bd9Sstevel@tonic-gate * other errors might need to be added to this list, for
10867c478bd9Sstevel@tonic-gate * the current supported mechanisms this is sufficient
10877c478bd9Sstevel@tonic-gate */
10887c478bd9Sstevel@tonic-gate if ((ldaprc == NS_LDAP_INTERNAL) &&
10897c478bd9Sstevel@tonic-gate (errorp->pwd_mgmt.status == NS_PASSWD_GOOD) &&
10907c478bd9Sstevel@tonic-gate ((errorp->status == LDAP_INAPPROPRIATE_AUTH) ||
10917c478bd9Sstevel@tonic-gate (errorp->status == LDAP_INVALID_CREDENTIALS))) {
10927c478bd9Sstevel@tonic-gate result = ldaprc;
10937c478bd9Sstevel@tonic-gate goto out;
10947c478bd9Sstevel@tonic-gate }
10957c478bd9Sstevel@tonic-gate
10967c478bd9Sstevel@tonic-gate /*
10977c478bd9Sstevel@tonic-gate * If there is error related to password policy,
10987c478bd9Sstevel@tonic-gate * return it to caller
10997c478bd9Sstevel@tonic-gate */
11007c478bd9Sstevel@tonic-gate if ((ldaprc == NS_LDAP_INTERNAL) &&
11017c478bd9Sstevel@tonic-gate errorp->pwd_mgmt.status != NS_PASSWD_GOOD) {
11027c478bd9Sstevel@tonic-gate *pwd_status = errorp->pwd_mgmt.status;
11037c478bd9Sstevel@tonic-gate result = ldaprc;
11047c478bd9Sstevel@tonic-gate goto out;
11057c478bd9Sstevel@tonic-gate } else
11067c478bd9Sstevel@tonic-gate *pwd_status = NS_PASSWD_GOOD;
11077c478bd9Sstevel@tonic-gate
11087c478bd9Sstevel@tonic-gate /* we don't really care about the error, just clean it up */
11097c478bd9Sstevel@tonic-gate if (errorp)
11107c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp);
11117c478bd9Sstevel@tonic-gate }
11127c478bd9Sstevel@tonic-gate if (authstried == 0) {
11137c478bd9Sstevel@tonic-gate syslog(LOG_ERR,
11147c478bd9Sstevel@tonic-gate "passwdutil: no legal LDAP authentication method configured");
11157c478bd9Sstevel@tonic-gate result = NS_LDAP_CONFIG;
11167c478bd9Sstevel@tonic-gate goto out;
11177c478bd9Sstevel@tonic-gate }
1118dd1104fbSMichen Chang result = NS_LDAP_OP_FAILED; /* map to PWU_DENIED */
11197c478bd9Sstevel@tonic-gate
11207c478bd9Sstevel@tonic-gate out:
11217c478bd9Sstevel@tonic-gate if (credp)
11227c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeCred(&credp);
11237c478bd9Sstevel@tonic-gate
11247c478bd9Sstevel@tonic-gate if (authpp)
11257c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&authpp);
11267c478bd9Sstevel@tonic-gate
11277c478bd9Sstevel@tonic-gate if (errorp)
11287c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp);
11297c478bd9Sstevel@tonic-gate
11307c478bd9Sstevel@tonic-gate return (result);
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate
11337c478bd9Sstevel@tonic-gate
11347c478bd9Sstevel@tonic-gate /*
113536e852a1SRaja Andra * ldap_putpwnam(name, oldpw, rep, buf)
11367c478bd9Sstevel@tonic-gate *
11377c478bd9Sstevel@tonic-gate * update the LDAP server with the attributes contained in 'buf'.
11387c478bd9Sstevel@tonic-gate */
11397c478bd9Sstevel@tonic-gate /*ARGSUSED*/
11407c478bd9Sstevel@tonic-gate int
ldap_putpwnam(const char * name,const char * oldpw,pwu_repository_t * rep,void * buf)1141*cbea7acaSDominik Hassler ldap_putpwnam(const char *name, const char *oldpw, pwu_repository_t *rep,
1142*cbea7acaSDominik Hassler void *buf)
11437c478bd9Sstevel@tonic-gate {
11447c478bd9Sstevel@tonic-gate int res;
11457c478bd9Sstevel@tonic-gate char *dn; /* dn of user whose attributes we are changing */
11467c478bd9Sstevel@tonic-gate char *binddn; /* dn of user who is performing the change */
11477c478bd9Sstevel@tonic-gate ns_ldap_error_t *errorp;
11487c478bd9Sstevel@tonic-gate ldapbuf_t *ldapbuf = (ldapbuf_t *)buf;
1149dd1104fbSMichen Chang ns_ldap_attr_t **pattrs = ldapbuf->pattrs;
1150dd1104fbSMichen Chang ns_ldap_attr_t **sattrs = ldapbuf->sattrs;
11517c478bd9Sstevel@tonic-gate struct passwd *pw;
11527c478bd9Sstevel@tonic-gate int pwd_status;
11537c478bd9Sstevel@tonic-gate uid_t uid;
11547c478bd9Sstevel@tonic-gate
11557c478bd9Sstevel@tonic-gate if (strcmp(name, "root") == 0)
11567c478bd9Sstevel@tonic-gate return (PWU_NOT_FOUND);
11577c478bd9Sstevel@tonic-gate
11587c478bd9Sstevel@tonic-gate /*
1159dd1104fbSMichen Chang * convert name of user whose attributes we are changing
1160dd1104fbSMichen Chang * to a distinguished name
1161dd1104fbSMichen Chang */
1162dd1104fbSMichen Chang res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp);
1163dd1104fbSMichen Chang if (res != NS_LDAP_SUCCESS)
1164dd1104fbSMichen Chang goto out;
1165dd1104fbSMichen Chang
1166dd1104fbSMichen Chang /* update shadow via ldap_cachemgr if it is enabled */
1167dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled &&
1168dd1104fbSMichen Chang sattrs != NULL && sattrs[0] != NULL) {
1169dd1104fbSMichen Chang /*
1170dd1104fbSMichen Chang * flag NS_LDAP_UPDATE_SHADOW indicates the shadow update
1171dd1104fbSMichen Chang * should be done via ldap_cachemgr
1172dd1104fbSMichen Chang */
1173dd1104fbSMichen Chang res = ldap_replaceattr(dn, sattrs, NULL, NULL, &pwd_status,
1174dd1104fbSMichen Chang NS_LDAP_UPDATE_SHADOW);
1175dd1104fbSMichen Chang goto out;
1176dd1104fbSMichen Chang }
1177dd1104fbSMichen Chang
1178dd1104fbSMichen Chang /*
11797c478bd9Sstevel@tonic-gate * The LDAP server checks whether we are permitted to perform
11807c478bd9Sstevel@tonic-gate * the requested change. We need to send the name of the user
11817c478bd9Sstevel@tonic-gate * who is executing this piece of code, together with his
11827c478bd9Sstevel@tonic-gate * current password to the server.
11837c478bd9Sstevel@tonic-gate * If this is executed by a normal user changing his/her own
11847c478bd9Sstevel@tonic-gate * password, this will simply be the OLD password that is to
11857c478bd9Sstevel@tonic-gate * be changed.
11867c478bd9Sstevel@tonic-gate * Specific case if the user who is executing this piece
11877c478bd9Sstevel@tonic-gate * of code is root. We will then issue the LDAP request
11887c478bd9Sstevel@tonic-gate * with the DN of the user we want to change the passwd of.
11897c478bd9Sstevel@tonic-gate */
11907c478bd9Sstevel@tonic-gate
11917c478bd9Sstevel@tonic-gate /*
11927c478bd9Sstevel@tonic-gate * create a dn for the user who is executing this code
11937c478bd9Sstevel@tonic-gate */
11947c478bd9Sstevel@tonic-gate uid = getuid();
11957c478bd9Sstevel@tonic-gate if (uid == 0) {
11967c478bd9Sstevel@tonic-gate if ((pw = getpwnam_from(name, rep, REP_LDAP)) == NULL) {
11977c478bd9Sstevel@tonic-gate res = NS_LDAP_OP_FAILED;
11987c478bd9Sstevel@tonic-gate goto out;
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate } else if ((pw = getpwuid_from(uid, rep, REP_LDAP)) == NULL) {
12017c478bd9Sstevel@tonic-gate /*
12027c478bd9Sstevel@tonic-gate * User executing this code is not known to the LDAP
12037c478bd9Sstevel@tonic-gate * server. This operation is to be denied
12047c478bd9Sstevel@tonic-gate */
12057c478bd9Sstevel@tonic-gate res = NS_LDAP_OP_FAILED;
12067c478bd9Sstevel@tonic-gate goto out;
12077c478bd9Sstevel@tonic-gate }
12087c478bd9Sstevel@tonic-gate
12097c478bd9Sstevel@tonic-gate res = __ns_ldap_uid2dn(pw->pw_name, &binddn, NULL, &errorp);
12107c478bd9Sstevel@tonic-gate if (res != NS_LDAP_SUCCESS)
12117c478bd9Sstevel@tonic-gate goto out;
12127c478bd9Sstevel@tonic-gate
1213dd1104fbSMichen Chang if (pattrs && pattrs[0] != NULL) {
1214dd1104fbSMichen Chang res = ldap_replaceattr(dn, pattrs, binddn, oldpw,
1215dd1104fbSMichen Chang &pwd_status, 0);
1216dd1104fbSMichen Chang } else
1217dd1104fbSMichen Chang res = NS_LDAP_OP_FAILED;
12187c478bd9Sstevel@tonic-gate
12197c478bd9Sstevel@tonic-gate out:
1220dd1104fbSMichen Chang free_ldapbuf(ldapbuf);
12217c478bd9Sstevel@tonic-gate free(dn);
12227c478bd9Sstevel@tonic-gate
12237c478bd9Sstevel@tonic-gate return (ldap_to_pwu_code(res, pwd_status));
12247c478bd9Sstevel@tonic-gate }
1225