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