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 5*dd1104fbSMichen Chang * Common Development and Distribution License (the "License"). 6*dd1104fbSMichen 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 /* 22*dd1104fbSMichen 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> 31*dd1104fbSMichen Chang #include <macros.h> 32*dd1104fbSMichen 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 47*dd1104fbSMichen Chang #define MAX_INT_LEN 11 /* 10+1 %d buflen for words/ints [not longs] */ 48*dd1104fbSMichen Chang 49*dd1104fbSMichen Chang #define STRDUP_OR_RET(to, from) \ 50*dd1104fbSMichen Chang if ((to = strdup(from)) == NULL) \ 51*dd1104fbSMichen Chang return (PWU_NOMEM); 52*dd1104fbSMichen Chang 53*dd1104fbSMichen Chang #define STRDUP_OR_ERR(to, from, err) \ 54*dd1104fbSMichen Chang if (((to) = strdup(from)) == NULL) \ 55*dd1104fbSMichen Chang (err) = PWU_NOMEM; 56*dd1104fbSMichen Chang 57*dd1104fbSMichen Chang #define NUM_TO_STR(to, from) \ 58*dd1104fbSMichen Chang { \ 59*dd1104fbSMichen Chang char nb[MAX_INT_LEN]; \ 60*dd1104fbSMichen Chang if (snprintf(nb, MAX_INT_LEN, "%d", (from)) >= MAX_INT_LEN) \ 61*dd1104fbSMichen Chang return (PWU_NOMEM); \ 62*dd1104fbSMichen Chang STRDUP_OR_RET(to, nb); \ 63*dd1104fbSMichen Chang } 64*dd1104fbSMichen Chang 65*dd1104fbSMichen Chang #define NEW_ATTR(p, i, attr, val) \ 66*dd1104fbSMichen Chang { \ 67*dd1104fbSMichen Chang p[i] = new_attr(attr, (val)); \ 68*dd1104fbSMichen Chang if (p[i] == NULL) \ 69*dd1104fbSMichen Chang return (PWU_NOMEM); \ 70*dd1104fbSMichen Chang i++; \ 71*dd1104fbSMichen Chang } 72*dd1104fbSMichen 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); 777c478bd9Sstevel@tonic-gate int ldap_putpwnam(char *name, char *oldpw, char *dummy, 787c478bd9Sstevel@tonic-gate pwu_repository_t *rep, void *buf); 797c478bd9Sstevel@tonic-gate int ldap_user_to_authenticate(char *name, pwu_repository_t *rep, 807c478bd9Sstevel@tonic-gate char **auth_user, int *privileged); 817c478bd9Sstevel@tonic-gate 827c478bd9Sstevel@tonic-gate /* 837c478bd9Sstevel@tonic-gate * ldap function pointer table, used by passwdutil_init to initialize 847c478bd9Sstevel@tonic-gate * the global Repository-OPerations table "rops" 857c478bd9Sstevel@tonic-gate */ 867c478bd9Sstevel@tonic-gate struct repops ldap_repops = { 877c478bd9Sstevel@tonic-gate NULL, /* checkhistory */ 887c478bd9Sstevel@tonic-gate ldap_getattr, 897c478bd9Sstevel@tonic-gate ldap_getpwnam, 907c478bd9Sstevel@tonic-gate ldap_update, 917c478bd9Sstevel@tonic-gate ldap_putpwnam, 927c478bd9Sstevel@tonic-gate ldap_user_to_authenticate, 937c478bd9Sstevel@tonic-gate NULL, /* lock */ 947c478bd9Sstevel@tonic-gate NULL /* unlock */ 957c478bd9Sstevel@tonic-gate }; 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate /* 987c478bd9Sstevel@tonic-gate * structure used to keep state between get/update/put calls 997c478bd9Sstevel@tonic-gate */ 1007c478bd9Sstevel@tonic-gate typedef struct { 1017c478bd9Sstevel@tonic-gate char *passwd; /* encrypted password */ 1027c478bd9Sstevel@tonic-gate struct passwd *pwd; 103*dd1104fbSMichen Chang ns_ldap_attr_t **pattrs; /* passwd attrs */ 104*dd1104fbSMichen Chang int npattrs; /* max attrs */ 105*dd1104fbSMichen Chang struct spwd *spwd; 106*dd1104fbSMichen Chang ns_ldap_attr_t **sattrs; /* passwd attrs */ 107*dd1104fbSMichen Chang int nsattrs; /* max attrs */ 108*dd1104fbSMichen Chang boolean_t shadow_update_enabled; /* shadow update configured */ 1097c478bd9Sstevel@tonic-gate } ldapbuf_t; 1107c478bd9Sstevel@tonic-gate 1117c478bd9Sstevel@tonic-gate /* 1127c478bd9Sstevel@tonic-gate * The following define's are taken from 1137c478bd9Sstevel@tonic-gate * usr/src/lib/nsswitch/ldap/common/getpwnam.c 1147c478bd9Sstevel@tonic-gate */ 1157c478bd9Sstevel@tonic-gate 1167c478bd9Sstevel@tonic-gate /* passwd attributes filters */ 1177c478bd9Sstevel@tonic-gate #define _PWD_CN "cn" 1187c478bd9Sstevel@tonic-gate #define _PWD_UID "uid" 1197c478bd9Sstevel@tonic-gate #define _PWD_USERPASSWORD "userpassword" 1207c478bd9Sstevel@tonic-gate #define _PWD_UIDNUMBER "uidnumber" 1217c478bd9Sstevel@tonic-gate #define _PWD_GIDNUMBER "gidnumber" 1227c478bd9Sstevel@tonic-gate #define _PWD_GECOS "gecos" 1237c478bd9Sstevel@tonic-gate #define _PWD_DESCRIPTION "description" 1247c478bd9Sstevel@tonic-gate #define _PWD_HOMEDIRECTORY "homedirectory" 1257c478bd9Sstevel@tonic-gate #define _PWD_LOGINSHELL "loginshell" 1267c478bd9Sstevel@tonic-gate 127*dd1104fbSMichen Chang #define _PWD_MAX_ATTR 10 /* 9+NULL */ 128*dd1104fbSMichen Chang 129*dd1104fbSMichen Chang /* shadow attributes filters */ 130*dd1104fbSMichen Chang #define _S_LASTCHANGE "shadowlastchange" 131*dd1104fbSMichen Chang #define _S_MIN "shadowmin" 132*dd1104fbSMichen Chang #define _S_MAX "shadowmax" 133*dd1104fbSMichen Chang #define _S_WARNING "shadowwarning" 134*dd1104fbSMichen Chang #define _S_INACTIVE "shadowinactive" 135*dd1104fbSMichen Chang #define _S_EXPIRE "shadowexpire" 136*dd1104fbSMichen Chang #define _S_FLAG "shadowflag" 137*dd1104fbSMichen Chang 138*dd1104fbSMichen Chang #define _S_MAX_ATTR 8 /* 7+NULL */ 139*dd1104fbSMichen Chang 140*dd1104fbSMichen Chang /* 141*dd1104fbSMichen Chang * Frees up an ldapbuf_t 142*dd1104fbSMichen Chang */ 143*dd1104fbSMichen Chang 144*dd1104fbSMichen Chang static void 145*dd1104fbSMichen Chang free_ldapbuf(ldapbuf_t *p) 146*dd1104fbSMichen Chang { 147*dd1104fbSMichen Chang int i; 148*dd1104fbSMichen Chang 149*dd1104fbSMichen Chang if (p == NULL) 150*dd1104fbSMichen Chang return; 151*dd1104fbSMichen Chang if (p->passwd) { 152*dd1104fbSMichen Chang (void) memset(p->passwd, 0, strlen(p->passwd)); 153*dd1104fbSMichen Chang free(p->passwd); 154*dd1104fbSMichen Chang } 155*dd1104fbSMichen Chang if (p->pwd) 156*dd1104fbSMichen Chang free_pwd(p->pwd); 157*dd1104fbSMichen Chang if (p->spwd) 158*dd1104fbSMichen Chang free_spwd(p->spwd); 159*dd1104fbSMichen Chang if (p->pattrs) { 160*dd1104fbSMichen Chang for (i = 0; i < p->npattrs; i++) { 161*dd1104fbSMichen Chang if (p->pattrs[i] != NULL) { 162*dd1104fbSMichen Chang free(p->pattrs[i]->attrvalue[0]); 163*dd1104fbSMichen Chang free(p->pattrs[i]); 164*dd1104fbSMichen Chang } 165*dd1104fbSMichen Chang } 166*dd1104fbSMichen Chang free(p->pattrs); 167*dd1104fbSMichen Chang } 168*dd1104fbSMichen Chang if (p->sattrs) { 169*dd1104fbSMichen Chang for (i = 0; i < p->nsattrs; i++) { 170*dd1104fbSMichen Chang if (p->sattrs[i] != NULL) { 171*dd1104fbSMichen Chang free(p->sattrs[i]->attrvalue[0]); 172*dd1104fbSMichen Chang free(p->sattrs[i]); 173*dd1104fbSMichen Chang } 174*dd1104fbSMichen Chang } 175*dd1104fbSMichen Chang free(p->sattrs); 176*dd1104fbSMichen Chang } 177*dd1104fbSMichen Chang } 178*dd1104fbSMichen Chang 1797c478bd9Sstevel@tonic-gate /* 1807c478bd9Sstevel@tonic-gate * int ldap_user_to_authenticate(user, rep, auth_user, privileged) 1817c478bd9Sstevel@tonic-gate * 182*dd1104fbSMichen Chang * If the Shadow Update functionality is enabled, then we check to 183*dd1104fbSMichen Chang * see if the caller has 0 as the euid or has all zone privs. If so, 184*dd1104fbSMichen Chang * the caller would be able to modify shadow(4) data stored on the 185*dd1104fbSMichen Chang * LDAP server. Otherwise, when LDAP Shadow Update is not enabled, 186*dd1104fbSMichen Chang * we can't determine whether the user is "privileged" in the LDAP 187*dd1104fbSMichen Chang * sense. The operation should be attempted and will succeed if the 188*dd1104fbSMichen Chang * user had privileges. For our purposes, we say that the user is 189*dd1104fbSMichen Chang * privileged if he/she is attempting to change another user's 190*dd1104fbSMichen Chang * password attributes. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate int 1937c478bd9Sstevel@tonic-gate ldap_user_to_authenticate(char *user, pwu_repository_t *rep, 1947c478bd9Sstevel@tonic-gate char **auth_user, int *privileged) 1957c478bd9Sstevel@tonic-gate { 1967c478bd9Sstevel@tonic-gate struct passwd *pw; 1977c478bd9Sstevel@tonic-gate uid_t uid; 1987c478bd9Sstevel@tonic-gate uid_t priviledged_uid; 1997c478bd9Sstevel@tonic-gate int res = PWU_SUCCESS; 2007c478bd9Sstevel@tonic-gate 2017c478bd9Sstevel@tonic-gate if (strcmp(user, "root") == 0) 2027c478bd9Sstevel@tonic-gate return (PWU_NOT_FOUND); 2037c478bd9Sstevel@tonic-gate 2047c478bd9Sstevel@tonic-gate if ((pw = getpwnam_from(user, rep, REP_LDAP)) == NULL) 2057c478bd9Sstevel@tonic-gate return (PWU_NOT_FOUND); 2067c478bd9Sstevel@tonic-gate 2077c478bd9Sstevel@tonic-gate uid = getuid(); 2087c478bd9Sstevel@tonic-gate 209*dd1104fbSMichen Chang /* 210*dd1104fbSMichen Chang * need equivalent of write access to /etc/shadow 211*dd1104fbSMichen Chang * the privilege escalation model is euid == 0 || all zone privs 212*dd1104fbSMichen Chang */ 213*dd1104fbSMichen Chang if (__ns_ldap_is_shadow_update_enabled()) { 214*dd1104fbSMichen Chang boolean_t priv; 215*dd1104fbSMichen Chang 216*dd1104fbSMichen Chang priv = (geteuid() == 0); 217*dd1104fbSMichen Chang if (!priv) { 218*dd1104fbSMichen Chang priv_set_t *ps = priv_allocset(); /* caller */ 219*dd1104fbSMichen Chang priv_set_t *zs; /* zone */ 220*dd1104fbSMichen Chang 221*dd1104fbSMichen Chang (void) getppriv(PRIV_EFFECTIVE, ps); 222*dd1104fbSMichen Chang zs = priv_str_to_set("zone", ",", NULL); 223*dd1104fbSMichen Chang priv = priv_isequalset(ps, zs); 224*dd1104fbSMichen Chang priv_freeset(ps); 225*dd1104fbSMichen Chang priv_freeset(zs); 226*dd1104fbSMichen Chang } 227*dd1104fbSMichen Chang /* 228*dd1104fbSMichen Chang * priv can change anyone's password, 229*dd1104fbSMichen Chang * only root isn't prompted. 230*dd1104fbSMichen Chang */ 231*dd1104fbSMichen Chang *privileged = 0; /* for proper prompting */ 232*dd1104fbSMichen Chang if (priv) { 233*dd1104fbSMichen Chang if (uid == 0) { 234*dd1104fbSMichen Chang *privileged = 1; 235*dd1104fbSMichen Chang *auth_user = NULL; 236*dd1104fbSMichen Chang return (res); 237*dd1104fbSMichen Chang } else if (uid == pw->pw_uid) { 238*dd1104fbSMichen Chang STRDUP_OR_ERR(*auth_user, user, res); 239*dd1104fbSMichen Chang return (res); 240*dd1104fbSMichen Chang } 241*dd1104fbSMichen Chang } 242*dd1104fbSMichen Chang 243*dd1104fbSMichen Chang return (PWU_DENIED); 244*dd1104fbSMichen Chang } 245*dd1104fbSMichen Chang 2467c478bd9Sstevel@tonic-gate if (uid == pw->pw_uid) { 247*dd1104fbSMichen Chang /* changing our own, not privileged */ 2487c478bd9Sstevel@tonic-gate *privileged = 0; 249*dd1104fbSMichen Chang STRDUP_OR_RET(*auth_user, user); 2507c478bd9Sstevel@tonic-gate } else { 2517c478bd9Sstevel@tonic-gate char pwd_buf[1024]; 2527c478bd9Sstevel@tonic-gate struct passwd pwr; 2537c478bd9Sstevel@tonic-gate 2547c478bd9Sstevel@tonic-gate *privileged = 1; 2557c478bd9Sstevel@tonic-gate /* 2567c478bd9Sstevel@tonic-gate * specific case for root 2577c478bd9Sstevel@tonic-gate * we want 'user' to be authenticated. 2587c478bd9Sstevel@tonic-gate */ 2597c478bd9Sstevel@tonic-gate if (uid == 0) { 2607c478bd9Sstevel@tonic-gate priviledged_uid = pw->pw_uid; 2617c478bd9Sstevel@tonic-gate } else { 2627c478bd9Sstevel@tonic-gate priviledged_uid = uid; 2637c478bd9Sstevel@tonic-gate } 2647c478bd9Sstevel@tonic-gate if (getpwuid_r(priviledged_uid, &pwr, pwd_buf, 2657c478bd9Sstevel@tonic-gate sizeof (pwd_buf)) != NULL) { 266*dd1104fbSMichen Chang STRDUP_OR_ERR(*auth_user, pwr.pw_name, res); 2677c478bd9Sstevel@tonic-gate } else { 2687c478bd9Sstevel@tonic-gate /* hmm. can't find name of current user...??? */ 2697c478bd9Sstevel@tonic-gate 270*dd1104fbSMichen Chang if ((*auth_user = malloc(MAX_INT_LEN)) == NULL) { 2717c478bd9Sstevel@tonic-gate res = PWU_NOMEM; 2727c478bd9Sstevel@tonic-gate } else { 273*dd1104fbSMichen Chang (void) snprintf(*auth_user, MAX_INT_LEN, "%d", 2747c478bd9Sstevel@tonic-gate (int)uid); 2757c478bd9Sstevel@tonic-gate } 2767c478bd9Sstevel@tonic-gate } 2777c478bd9Sstevel@tonic-gate } 2787c478bd9Sstevel@tonic-gate 2797c478bd9Sstevel@tonic-gate return (res); 2807c478bd9Sstevel@tonic-gate } 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate /* 2837c478bd9Sstevel@tonic-gate * int ldap_getattr(name, item, rep) 2847c478bd9Sstevel@tonic-gate * 2857c478bd9Sstevel@tonic-gate * retrieve attributes specified in "item" for user "name". 2867c478bd9Sstevel@tonic-gate */ 2877c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 2887c478bd9Sstevel@tonic-gate int 2897c478bd9Sstevel@tonic-gate ldap_getattr(char *name, attrlist *items, pwu_repository_t *rep) 2907c478bd9Sstevel@tonic-gate { 291*dd1104fbSMichen Chang attrlist *w; 2927c478bd9Sstevel@tonic-gate int res; 293*dd1104fbSMichen Chang ldapbuf_t *ldapbuf; 2947c478bd9Sstevel@tonic-gate struct passwd *pw = NULL; 2957c478bd9Sstevel@tonic-gate struct spwd *spw = NULL; 2967c478bd9Sstevel@tonic-gate 297*dd1104fbSMichen Chang res = ldap_getpwnam(name, items, rep, (void **)&ldapbuf); 2987c478bd9Sstevel@tonic-gate if (res != PWU_SUCCESS) 299*dd1104fbSMichen Chang return (res); 3007c478bd9Sstevel@tonic-gate 301*dd1104fbSMichen Chang pw = ldapbuf->pwd; 302*dd1104fbSMichen Chang spw = ldapbuf->spwd; 3037c478bd9Sstevel@tonic-gate 3047c478bd9Sstevel@tonic-gate for (w = items; res == PWU_SUCCESS && w != NULL; w = w->next) { 3057c478bd9Sstevel@tonic-gate switch (w->type) { 3067c478bd9Sstevel@tonic-gate case ATTR_NAME: 307*dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_name, res); 3087c478bd9Sstevel@tonic-gate break; 3097c478bd9Sstevel@tonic-gate case ATTR_COMMENT: 310*dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_comment, res); 3117c478bd9Sstevel@tonic-gate break; 3127c478bd9Sstevel@tonic-gate case ATTR_GECOS: 313*dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_gecos, res); 3147c478bd9Sstevel@tonic-gate break; 3157c478bd9Sstevel@tonic-gate case ATTR_HOMEDIR: 316*dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_dir, res); 3177c478bd9Sstevel@tonic-gate break; 3187c478bd9Sstevel@tonic-gate case ATTR_SHELL: 319*dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_shell, res); 3207c478bd9Sstevel@tonic-gate break; 3217c478bd9Sstevel@tonic-gate case ATTR_PASSWD: 3227c478bd9Sstevel@tonic-gate case ATTR_PASSWD_SERVER_POLICY: 323*dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, spw->sp_pwdp, res); 3247c478bd9Sstevel@tonic-gate break; 3257c478bd9Sstevel@tonic-gate case ATTR_AGE: 326*dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, pw->pw_age, res); 3277c478bd9Sstevel@tonic-gate break; 3287c478bd9Sstevel@tonic-gate case ATTR_REP_NAME: 329*dd1104fbSMichen Chang STRDUP_OR_ERR(w->data.val_s, "ldap", res); 3307c478bd9Sstevel@tonic-gate break; 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* integer values */ 3337c478bd9Sstevel@tonic-gate case ATTR_UID: 3347c478bd9Sstevel@tonic-gate w->data.val_i = pw->pw_uid; 3357c478bd9Sstevel@tonic-gate break; 3367c478bd9Sstevel@tonic-gate case ATTR_GID: 3377c478bd9Sstevel@tonic-gate w->data.val_i = pw->pw_gid; 3387c478bd9Sstevel@tonic-gate break; 3397c478bd9Sstevel@tonic-gate case ATTR_LSTCHG: 340*dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled) 341*dd1104fbSMichen Chang w->data.val_i = spw->sp_lstchg; 342*dd1104fbSMichen Chang else 3437c478bd9Sstevel@tonic-gate w->data.val_i = -1; 3447c478bd9Sstevel@tonic-gate break; 3457c478bd9Sstevel@tonic-gate case ATTR_MIN: 346*dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled) 347*dd1104fbSMichen Chang w->data.val_i = spw->sp_min; 348*dd1104fbSMichen Chang else 3497c478bd9Sstevel@tonic-gate w->data.val_i = -1; 3507c478bd9Sstevel@tonic-gate break; 3517c478bd9Sstevel@tonic-gate case ATTR_MAX: 352*dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled) 353*dd1104fbSMichen Chang w->data.val_i = spw->sp_max; 354*dd1104fbSMichen Chang else 3557c478bd9Sstevel@tonic-gate w->data.val_i = -1; 3567c478bd9Sstevel@tonic-gate break; 3577c478bd9Sstevel@tonic-gate case ATTR_WARN: 358*dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled) 359*dd1104fbSMichen Chang w->data.val_i = spw->sp_warn; 360*dd1104fbSMichen Chang else 3617c478bd9Sstevel@tonic-gate w->data.val_i = -1; 3627c478bd9Sstevel@tonic-gate break; 3637c478bd9Sstevel@tonic-gate case ATTR_INACT: 364*dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled) 365*dd1104fbSMichen Chang w->data.val_i = spw->sp_inact; 366*dd1104fbSMichen Chang else 3677c478bd9Sstevel@tonic-gate w->data.val_i = -1; 3687c478bd9Sstevel@tonic-gate break; 3697c478bd9Sstevel@tonic-gate case ATTR_EXPIRE: 370*dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled) 371*dd1104fbSMichen Chang w->data.val_i = spw->sp_expire; 372*dd1104fbSMichen Chang else 3737c478bd9Sstevel@tonic-gate w->data.val_i = -1; 3747c478bd9Sstevel@tonic-gate break; 3757c478bd9Sstevel@tonic-gate case ATTR_FLAG: 376*dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled) 377*dd1104fbSMichen Chang w->data.val_i = spw->sp_flag; 378*dd1104fbSMichen Chang break; 379*dd1104fbSMichen Chang case ATTR_FAILED_LOGINS: 380*dd1104fbSMichen Chang w->data.val_i = spw->sp_flag & FAILCOUNT_MASK; 3817c478bd9Sstevel@tonic-gate break; 3827c478bd9Sstevel@tonic-gate default: 3837c478bd9Sstevel@tonic-gate break; 3847c478bd9Sstevel@tonic-gate } 3857c478bd9Sstevel@tonic-gate } 3867c478bd9Sstevel@tonic-gate 3877c478bd9Sstevel@tonic-gate out: 388*dd1104fbSMichen Chang free_ldapbuf(ldapbuf); 389*dd1104fbSMichen Chang free(ldapbuf); 3907c478bd9Sstevel@tonic-gate return (res); 3917c478bd9Sstevel@tonic-gate } 3927c478bd9Sstevel@tonic-gate 3937c478bd9Sstevel@tonic-gate /* 3947c478bd9Sstevel@tonic-gate * int ldap_getpwnam(name, items, rep, buf) 3957c478bd9Sstevel@tonic-gate * 3967c478bd9Sstevel@tonic-gate * There is no need to get the old values from the ldap 3977c478bd9Sstevel@tonic-gate * server, as the update will update each item individually. 3987c478bd9Sstevel@tonic-gate * Therefore, we only allocate a buffer that will be used by 3997c478bd9Sstevel@tonic-gate * _update and _putpwnam to hold the attributes to update. 4007c478bd9Sstevel@tonic-gate * 4017c478bd9Sstevel@tonic-gate * Only when we're about to update a password, we need to retrieve 4027c478bd9Sstevel@tonic-gate * the old password since it contains salt-information. 4037c478bd9Sstevel@tonic-gate */ 4047c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4057c478bd9Sstevel@tonic-gate int 4067c478bd9Sstevel@tonic-gate ldap_getpwnam(char *name, attrlist *items, pwu_repository_t *rep, 4077c478bd9Sstevel@tonic-gate void **buf) 4087c478bd9Sstevel@tonic-gate { 4097c478bd9Sstevel@tonic-gate ldapbuf_t *ldapbuf; 410*dd1104fbSMichen Chang int res = PWU_NOMEM; 4117c478bd9Sstevel@tonic-gate 412*dd1104fbSMichen Chang /* 413*dd1104fbSMichen Chang * [sp]attrs is treated as NULL terminated 414*dd1104fbSMichen Chang */ 4157c478bd9Sstevel@tonic-gate 4167c478bd9Sstevel@tonic-gate ldapbuf = calloc(1, sizeof (ldapbuf_t)); 4177c478bd9Sstevel@tonic-gate if (ldapbuf == NULL) 4187c478bd9Sstevel@tonic-gate return (PWU_NOMEM); 4197c478bd9Sstevel@tonic-gate 420*dd1104fbSMichen Chang ldapbuf->pattrs = calloc(_PWD_MAX_ATTR, sizeof (ns_ldap_attr_t *)); 421*dd1104fbSMichen Chang if (ldapbuf->pattrs == NULL) 422*dd1104fbSMichen Chang goto out; 423*dd1104fbSMichen Chang ldapbuf->npattrs = _PWD_MAX_ATTR; 4247c478bd9Sstevel@tonic-gate 425*dd1104fbSMichen Chang ldapbuf->sattrs = calloc(_S_MAX_ATTR, sizeof (ns_ldap_attr_t *)); 426*dd1104fbSMichen Chang if (ldapbuf->sattrs == NULL) 427*dd1104fbSMichen Chang goto out; 428*dd1104fbSMichen Chang ldapbuf->nsattrs = _S_MAX_ATTR; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate res = dup_pw(&ldapbuf->pwd, getpwnam_from(name, rep, REP_LDAP)); 4317c478bd9Sstevel@tonic-gate if (res != PWU_SUCCESS) 432*dd1104fbSMichen Chang goto out; 4337c478bd9Sstevel@tonic-gate 434*dd1104fbSMichen Chang res = dup_spw(&ldapbuf->spwd, getspnam_from(name, rep, REP_LDAP)); 435*dd1104fbSMichen Chang if (res != PWU_SUCCESS) 436*dd1104fbSMichen Chang goto out; 437*dd1104fbSMichen Chang else { 438*dd1104fbSMichen Chang char *spw = ldapbuf->spwd->sp_pwdp; 439*dd1104fbSMichen Chang if (spw != NULL && *spw != '\0') { 440*dd1104fbSMichen Chang ldapbuf->passwd = strdup(spw); 4417c478bd9Sstevel@tonic-gate if (ldapbuf->passwd == NULL) 442*dd1104fbSMichen Chang goto out; 443*dd1104fbSMichen Chang } else 444*dd1104fbSMichen Chang ldapbuf->passwd = NULL; 4457c478bd9Sstevel@tonic-gate } 4467c478bd9Sstevel@tonic-gate 447*dd1104fbSMichen Chang /* remember if shadow update is enabled */ 448*dd1104fbSMichen Chang ldapbuf->shadow_update_enabled = __ns_ldap_is_shadow_update_enabled(); 449*dd1104fbSMichen Chang 450*dd1104fbSMichen Chang *buf = (void *)ldapbuf; 451*dd1104fbSMichen Chang return (PWU_SUCCESS); 452*dd1104fbSMichen Chang 453*dd1104fbSMichen Chang out: 454*dd1104fbSMichen Chang free_ldapbuf(ldapbuf); 455*dd1104fbSMichen Chang free(ldapbuf); 456*dd1104fbSMichen Chang return (res); 4577c478bd9Sstevel@tonic-gate } 4587c478bd9Sstevel@tonic-gate 4597c478bd9Sstevel@tonic-gate /* 4607c478bd9Sstevel@tonic-gate * new_attr(name, value) 4617c478bd9Sstevel@tonic-gate * 4627c478bd9Sstevel@tonic-gate * create a new LDAP attribute to be sent to the server 4637c478bd9Sstevel@tonic-gate */ 4647c478bd9Sstevel@tonic-gate ns_ldap_attr_t * 4657c478bd9Sstevel@tonic-gate new_attr(char *name, char *value) 4667c478bd9Sstevel@tonic-gate { 4677c478bd9Sstevel@tonic-gate ns_ldap_attr_t *tmp; 4687c478bd9Sstevel@tonic-gate 4697c478bd9Sstevel@tonic-gate tmp = malloc(sizeof (*tmp)); 4707c478bd9Sstevel@tonic-gate if (tmp != NULL) { 4717c478bd9Sstevel@tonic-gate tmp->attrname = name; 4727c478bd9Sstevel@tonic-gate tmp->attrvalue = (char **)calloc(2, sizeof (char *)); 4737c478bd9Sstevel@tonic-gate if (tmp->attrvalue == NULL) { 4747c478bd9Sstevel@tonic-gate free(tmp); 4757c478bd9Sstevel@tonic-gate return (NULL); 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate tmp->attrvalue[0] = value; 4787c478bd9Sstevel@tonic-gate tmp->value_count = 1; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate 4817c478bd9Sstevel@tonic-gate return (tmp); 4827c478bd9Sstevel@tonic-gate } 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate /* 485*dd1104fbSMichen Chang * max_present(list) 486*dd1104fbSMichen Chang * 487*dd1104fbSMichen Chang * returns '1' if a ATTR_MAX with value != -1 is present. (in other words: 488*dd1104fbSMichen Chang * if password aging is to be turned on). 489*dd1104fbSMichen Chang */ 490*dd1104fbSMichen Chang static int 491*dd1104fbSMichen Chang max_present(attrlist *list) 492*dd1104fbSMichen Chang { 493*dd1104fbSMichen Chang while (list != NULL) 494*dd1104fbSMichen Chang if (list->type == ATTR_MAX && list->data.val_i != -1) 495*dd1104fbSMichen Chang return (1); 496*dd1104fbSMichen Chang else 497*dd1104fbSMichen Chang list = list->next; 498*dd1104fbSMichen Chang return (0); 499*dd1104fbSMichen Chang } 500*dd1104fbSMichen Chang 501*dd1104fbSMichen Chang /* 502*dd1104fbSMichen Chang * attr_addmod(attrs, idx, item, val) 503*dd1104fbSMichen Chang * 504*dd1104fbSMichen Chang * Adds or updates attribute 'item' in ldap_attrs list to value 505*dd1104fbSMichen Chang * update idx if item is added 506*dd1104fbSMichen Chang * return: -1 - PWU_NOMEM/error, 0 - success 507*dd1104fbSMichen Chang */ 508*dd1104fbSMichen Chang static int 509*dd1104fbSMichen Chang attr_addmod(ns_ldap_attr_t **attrs, int *idx, char *item, int value) 510*dd1104fbSMichen Chang { 511*dd1104fbSMichen Chang char numbuf[MAX_INT_LEN], *strp; 512*dd1104fbSMichen Chang int i; 513*dd1104fbSMichen Chang 514*dd1104fbSMichen Chang /* stringize the value or abort */ 515*dd1104fbSMichen Chang if (snprintf(numbuf, MAX_INT_LEN, "%d", value) >= MAX_INT_LEN) 516*dd1104fbSMichen Chang return (-1); 517*dd1104fbSMichen Chang 518*dd1104fbSMichen Chang /* check for existence and modify existing */ 519*dd1104fbSMichen Chang for (i = 0; i < *idx; i++) { 520*dd1104fbSMichen Chang if (attrs[i] != NULL && 521*dd1104fbSMichen Chang strcmp(item, attrs[i]->attrname) == 0) { 522*dd1104fbSMichen Chang strp = strdup(numbuf); 523*dd1104fbSMichen Chang if (strp == NULL) 524*dd1104fbSMichen Chang return (-1); 525*dd1104fbSMichen Chang free(attrs[i]->attrvalue[0]); 526*dd1104fbSMichen Chang attrs[i]->attrvalue[0] = strp; 527*dd1104fbSMichen Chang return (0); 528*dd1104fbSMichen Chang } 529*dd1104fbSMichen Chang } 530*dd1104fbSMichen Chang /* else add */ 531*dd1104fbSMichen Chang strp = strdup(numbuf); 532*dd1104fbSMichen Chang if (strp == NULL) 533*dd1104fbSMichen Chang return (-1); 534*dd1104fbSMichen Chang attrs[*idx] = new_attr(item, strp); 535*dd1104fbSMichen Chang if (attrs[*idx] == NULL) 536*dd1104fbSMichen Chang return (-1); 537*dd1104fbSMichen Chang (*idx)++; 538*dd1104fbSMichen Chang return (0); 539*dd1104fbSMichen Chang } 540*dd1104fbSMichen Chang 541*dd1104fbSMichen Chang /* 5427c478bd9Sstevel@tonic-gate * ldap_update(items, rep, buf) 5437c478bd9Sstevel@tonic-gate * 5447c478bd9Sstevel@tonic-gate * create LDAP attributes in 'buf' for each attribute in 'items'. 5457c478bd9Sstevel@tonic-gate */ 5467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 5477c478bd9Sstevel@tonic-gate int 5487c478bd9Sstevel@tonic-gate ldap_update(attrlist *items, pwu_repository_t *rep, void *buf) 5497c478bd9Sstevel@tonic-gate { 5507c478bd9Sstevel@tonic-gate attrlist *p; 5517c478bd9Sstevel@tonic-gate ldapbuf_t *ldapbuf = (ldapbuf_t *)buf; 552*dd1104fbSMichen Chang struct spwd *spw; 553*dd1104fbSMichen Chang ns_ldap_attr_t **pattrs = ldapbuf->pattrs; 554*dd1104fbSMichen Chang int pidx = 0; 555*dd1104fbSMichen Chang ns_ldap_attr_t **sattrs = ldapbuf->sattrs; 556*dd1104fbSMichen Chang int sidx = 0; 5577c478bd9Sstevel@tonic-gate char *pwd, *val; 5587c478bd9Sstevel@tonic-gate char *salt; 5597c478bd9Sstevel@tonic-gate size_t cryptlen; 560*dd1104fbSMichen Chang int len; 561*dd1104fbSMichen Chang int count; 562*dd1104fbSMichen Chang int rc = PWU_SUCCESS; 563*dd1104fbSMichen Chang int aging_needed = 0; 564*dd1104fbSMichen Chang int aging_set = 0; 565*dd1104fbSMichen Chang int disable_aging; 566*dd1104fbSMichen Chang 567*dd1104fbSMichen Chang spw = ldapbuf->spwd; 568*dd1104fbSMichen Chang 569*dd1104fbSMichen Chang /* 570*dd1104fbSMichen Chang * if sp_max==0 and shadow update is enabled: 571*dd1104fbSMichen Chang * disable passwd aging after updating the password 572*dd1104fbSMichen Chang */ 573*dd1104fbSMichen Chang disable_aging = (spw != NULL && spw->sp_max == 0 && 574*dd1104fbSMichen Chang ldapbuf->shadow_update_enabled); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate for (p = items; p != NULL; p = p->next) { 5777c478bd9Sstevel@tonic-gate switch (p->type) { 5787c478bd9Sstevel@tonic-gate case ATTR_PASSWD: 579*dd1104fbSMichen Chang /* 580*dd1104fbSMichen Chang * There is a special case for ldap: if the 581*dd1104fbSMichen Chang * password is to be deleted (-d to passwd), 582*dd1104fbSMichen Chang * p->data.val_s will be NULL. 583*dd1104fbSMichen Chang */ 584*dd1104fbSMichen Chang if (p->data.val_s == NULL) { 585*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 586*dd1104fbSMichen Chang return (PWU_CHANGE_NOT_ALLOWED); 587*dd1104fbSMichen Chang cryptlen = 588*dd1104fbSMichen Chang sizeof ("{crypt}" NS_LDAP_NO_UNIX_PASSWORD); 589*dd1104fbSMichen Chang val = malloc(cryptlen); 590*dd1104fbSMichen Chang if (val == NULL) 591*dd1104fbSMichen Chang return (PWU_NOMEM); 592*dd1104fbSMichen Chang (void) snprintf(val, cryptlen, 593*dd1104fbSMichen Chang "{crypt}" NS_LDAP_NO_UNIX_PASSWORD); 594*dd1104fbSMichen Chang } else { /* not deleting password */ 595*dd1104fbSMichen Chang salt = crypt_gensalt(ldapbuf->passwd, 596*dd1104fbSMichen Chang ldapbuf->pwd); 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate if (salt == NULL) { 5997c478bd9Sstevel@tonic-gate if (errno == ENOMEM) 6007c478bd9Sstevel@tonic-gate return (PWU_NOMEM); 601*dd1104fbSMichen Chang 6027c478bd9Sstevel@tonic-gate /* algorithm problem? */ 6037c478bd9Sstevel@tonic-gate syslog(LOG_AUTH | LOG_ALERT, 6047c478bd9Sstevel@tonic-gate "passwdutil: crypt_gensalt " 6057c478bd9Sstevel@tonic-gate "%m"); 6067c478bd9Sstevel@tonic-gate return (PWU_UPDATE_FAILED); 6077c478bd9Sstevel@tonic-gate } 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate pwd = crypt(p->data.val_s, salt); 6107c478bd9Sstevel@tonic-gate free(salt); 6117c478bd9Sstevel@tonic-gate cryptlen = strlen(pwd) + sizeof ("{crypt}"); 6127c478bd9Sstevel@tonic-gate val = malloc(cryptlen); 6137c478bd9Sstevel@tonic-gate if (val == NULL) 6147c478bd9Sstevel@tonic-gate return (PWU_NOMEM); 615*dd1104fbSMichen Chang (void) snprintf(val, cryptlen, 616*dd1104fbSMichen Chang "{crypt}%s", pwd); 617*dd1104fbSMichen Chang } 6187c478bd9Sstevel@tonic-gate 619*dd1104fbSMichen Chang /* 620*dd1104fbSMichen Chang * If not managing passwordAccount, 621*dd1104fbSMichen Chang * insert the new password in the 622*dd1104fbSMichen Chang * passwd attr array and break. 623*dd1104fbSMichen Chang */ 624*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) { 625*dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, 626*dd1104fbSMichen Chang _PWD_USERPASSWORD, val); 6277c478bd9Sstevel@tonic-gate break; 628*dd1104fbSMichen Chang } 629*dd1104fbSMichen Chang 630*dd1104fbSMichen Chang /* 631*dd1104fbSMichen Chang * Managing passwordAccount, insert the 632*dd1104fbSMichen Chang * new password, along with lastChange and 633*dd1104fbSMichen Chang * shadowFlag, in the shadow attr array. 634*dd1104fbSMichen Chang */ 635*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, val); 636*dd1104fbSMichen Chang 637*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE, 638*dd1104fbSMichen Chang DAY_NOW_32) < 0) 639*dd1104fbSMichen Chang return (PWU_NOMEM); 640*dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32; 641*dd1104fbSMichen Chang 642*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_FLAG, 643*dd1104fbSMichen Chang spw->sp_flag & ~FAILCOUNT_MASK) < 0) 644*dd1104fbSMichen Chang return (PWU_NOMEM); 645*dd1104fbSMichen Chang spw->sp_flag &= ~FAILCOUNT_MASK; /* reset count */ 646*dd1104fbSMichen Chang aging_needed = 1; 647*dd1104fbSMichen Chang break; 648*dd1104fbSMichen Chang case ATTR_PASSWD_SERVER_POLICY: 6497c478bd9Sstevel@tonic-gate /* 6507c478bd9Sstevel@tonic-gate * For server policy, don't crypt the password, 6517c478bd9Sstevel@tonic-gate * send the password as is to the server and 6527c478bd9Sstevel@tonic-gate * let the LDAP server do its own password 6537c478bd9Sstevel@tonic-gate * encryption 6547c478bd9Sstevel@tonic-gate */ 655*dd1104fbSMichen Chang STRDUP_OR_RET(val, p->data.val_s); 6567c478bd9Sstevel@tonic-gate 657*dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_USERPASSWORD, val); 6587c478bd9Sstevel@tonic-gate break; 6597c478bd9Sstevel@tonic-gate case ATTR_COMMENT: 6607c478bd9Sstevel@tonic-gate /* XX correct? */ 661*dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_DESCRIPTION, p->data.val_s); 6627c478bd9Sstevel@tonic-gate break; 6637c478bd9Sstevel@tonic-gate case ATTR_GECOS: 664*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) { 665*dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_GECOS, 666*dd1104fbSMichen Chang p->data.val_s); 667*dd1104fbSMichen Chang } else { 668*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_GECOS, 669*dd1104fbSMichen Chang p->data.val_s); 670*dd1104fbSMichen Chang } 6717c478bd9Sstevel@tonic-gate break; 6727c478bd9Sstevel@tonic-gate case ATTR_HOMEDIR: 673*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) { 674*dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_HOMEDIRECTORY, 6757c478bd9Sstevel@tonic-gate p->data.val_s); 676*dd1104fbSMichen Chang } else { 677*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_HOMEDIRECTORY, 678*dd1104fbSMichen Chang p->data.val_s); 679*dd1104fbSMichen Chang } 6807c478bd9Sstevel@tonic-gate break; 6817c478bd9Sstevel@tonic-gate case ATTR_SHELL: 682*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) { 683*dd1104fbSMichen Chang NEW_ATTR(pattrs, pidx, _PWD_LOGINSHELL, 684*dd1104fbSMichen Chang p->data.val_s); 685*dd1104fbSMichen Chang } else { 686*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_LOGINSHELL, 687*dd1104fbSMichen Chang p->data.val_s); 688*dd1104fbSMichen Chang } 6897c478bd9Sstevel@tonic-gate break; 690*dd1104fbSMichen Chang /* We don't update NAME, UID, GID */ 6917c478bd9Sstevel@tonic-gate case ATTR_NAME: 6927c478bd9Sstevel@tonic-gate case ATTR_UID: 6937c478bd9Sstevel@tonic-gate case ATTR_GID: 694*dd1104fbSMichen Chang /* Unsupported item */ 6957c478bd9Sstevel@tonic-gate case ATTR_AGE: 696*dd1104fbSMichen Chang break; 697*dd1104fbSMichen Chang case ATTR_LOCK_ACCOUNT: 698*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 699*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 700*dd1104fbSMichen Chang if (spw->sp_pwdp == NULL) { 701*dd1104fbSMichen Chang spw->sp_pwdp = LOCKSTRING; 702*dd1104fbSMichen Chang } else if (strncmp(spw->sp_pwdp, LOCKSTRING, 703*dd1104fbSMichen Chang sizeof (LOCKSTRING)-1) != 0) { 704*dd1104fbSMichen Chang len = sizeof (LOCKSTRING)-1 + 705*dd1104fbSMichen Chang strlen(spw->sp_pwdp) + 1 + 706*dd1104fbSMichen Chang sizeof ("{crypt}"); 707*dd1104fbSMichen Chang pwd = malloc(len); 708*dd1104fbSMichen Chang if (pwd == NULL) { 709*dd1104fbSMichen Chang return (PWU_NOMEM); 710*dd1104fbSMichen Chang } 711*dd1104fbSMichen Chang (void) strlcpy(pwd, "{crypt}", len); 712*dd1104fbSMichen Chang (void) strlcat(pwd, LOCKSTRING, len); 713*dd1104fbSMichen Chang (void) strlcat(pwd, spw->sp_pwdp, len); 714*dd1104fbSMichen Chang free(spw->sp_pwdp); 715*dd1104fbSMichen Chang spw->sp_pwdp = pwd; 716*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, 717*dd1104fbSMichen Chang spw->sp_pwdp); 718*dd1104fbSMichen Chang } 719*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE, 720*dd1104fbSMichen Chang DAY_NOW_32) < 0) 721*dd1104fbSMichen Chang return (PWU_NOMEM); 722*dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32; 723*dd1104fbSMichen Chang break; 724*dd1104fbSMichen Chang 725*dd1104fbSMichen Chang case ATTR_UNLOCK_ACCOUNT: 726*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 727*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 728*dd1104fbSMichen Chang if (spw->sp_pwdp && 729*dd1104fbSMichen Chang strncmp(spw->sp_pwdp, LOCKSTRING, 730*dd1104fbSMichen Chang sizeof (LOCKSTRING)-1) == 0) { 731*dd1104fbSMichen Chang len = (sizeof ("{crypt}") - 732*dd1104fbSMichen Chang sizeof (LOCKSTRING)) + 733*dd1104fbSMichen Chang strlen(spw->sp_pwdp) + 1; 734*dd1104fbSMichen Chang pwd = malloc(len); 735*dd1104fbSMichen Chang if (pwd == NULL) { 736*dd1104fbSMichen Chang return (PWU_NOMEM); 737*dd1104fbSMichen Chang } 738*dd1104fbSMichen Chang (void) strlcpy(pwd, "{crypt}", len); 739*dd1104fbSMichen Chang (void) strlcat(pwd, spw->sp_pwdp + 740*dd1104fbSMichen Chang sizeof (LOCKSTRING)-1, len); 741*dd1104fbSMichen Chang free(spw->sp_pwdp); 742*dd1104fbSMichen Chang spw->sp_pwdp = pwd; 743*dd1104fbSMichen Chang 744*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, 745*dd1104fbSMichen Chang spw->sp_pwdp); 746*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE, 747*dd1104fbSMichen Chang DAY_NOW_32) < 0) 748*dd1104fbSMichen Chang return (PWU_NOMEM); 749*dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32; 750*dd1104fbSMichen Chang } 751*dd1104fbSMichen Chang break; 752*dd1104fbSMichen Chang 753*dd1104fbSMichen Chang case ATTR_NOLOGIN_ACCOUNT: 754*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 755*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 756*dd1104fbSMichen Chang free(spw->sp_pwdp); 757*dd1104fbSMichen Chang STRDUP_OR_RET(spw->sp_pwdp, "{crypt}" NOLOGINSTRING); 758*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _PWD_USERPASSWORD, spw->sp_pwdp); 759*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_LASTCHANGE, 760*dd1104fbSMichen Chang DAY_NOW_32) < 0) 761*dd1104fbSMichen Chang return (PWU_NOMEM); 762*dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32; 763*dd1104fbSMichen Chang break; 764*dd1104fbSMichen Chang 765*dd1104fbSMichen Chang case ATTR_EXPIRE_PASSWORD: 766*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 767*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 768*dd1104fbSMichen Chang NUM_TO_STR(val, 0); 769*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val); 770*dd1104fbSMichen Chang break; 771*dd1104fbSMichen Chang 7727c478bd9Sstevel@tonic-gate case ATTR_LSTCHG: 773*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 774*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 775*dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i); 776*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_LASTCHANGE, val); 777*dd1104fbSMichen Chang break; 778*dd1104fbSMichen Chang 7797c478bd9Sstevel@tonic-gate case ATTR_MIN: 780*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 781*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 782*dd1104fbSMichen Chang if (spw->sp_max == -1 && p->data.val_i != -1 && 783*dd1104fbSMichen Chang max_present(p->next) == 0) 784*dd1104fbSMichen Chang return (PWU_AGING_DISABLED); 785*dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i); 786*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_MIN, val); 787*dd1104fbSMichen Chang aging_set = 1; 788*dd1104fbSMichen Chang break; 789*dd1104fbSMichen Chang 7907c478bd9Sstevel@tonic-gate case ATTR_MAX: 791*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 792*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 793*dd1104fbSMichen Chang if (p->data.val_i == -1) { 794*dd1104fbSMichen Chang /* Turn off aging. Reset min and warn too */ 795*dd1104fbSMichen Chang spw->sp_max = spw->sp_min = spw->sp_warn = -1; 796*dd1104fbSMichen Chang NUM_TO_STR(val, -1); 797*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_MIN, val); 798*dd1104fbSMichen Chang NUM_TO_STR(val, -1); 799*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_WARNING, val); 800*dd1104fbSMichen Chang } else { 801*dd1104fbSMichen Chang /* Turn account aging on */ 802*dd1104fbSMichen Chang if (spw->sp_min == -1) { 803*dd1104fbSMichen Chang /* 804*dd1104fbSMichen Chang * minage was not set with command- 805*dd1104fbSMichen Chang * line option: set to zero 806*dd1104fbSMichen Chang */ 807*dd1104fbSMichen Chang spw->sp_min = 0; 808*dd1104fbSMichen Chang NUM_TO_STR(val, 0); 809*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_MIN, 810*dd1104fbSMichen Chang val); 811*dd1104fbSMichen Chang } 812*dd1104fbSMichen Chang /* 813*dd1104fbSMichen Chang * If aging was turned off, we update lstchg. 814*dd1104fbSMichen Chang * We take care not to update lstchg if the 815*dd1104fbSMichen Chang * user has no password, otherwise the user 816*dd1104fbSMichen Chang * might not be required to provide a password 817*dd1104fbSMichen Chang * the next time [s]he logs in. 818*dd1104fbSMichen Chang * 819*dd1104fbSMichen Chang * Also, if lstchg != -1 (i.e., not set) 820*dd1104fbSMichen Chang * we keep the old value. 821*dd1104fbSMichen Chang */ 822*dd1104fbSMichen Chang if (spw->sp_max == -1 && 823*dd1104fbSMichen Chang spw->sp_pwdp != NULL && *spw->sp_pwdp && 824*dd1104fbSMichen Chang spw->sp_lstchg == -1) { 825*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, 826*dd1104fbSMichen Chang _S_LASTCHANGE, 827*dd1104fbSMichen Chang DAY_NOW_32) < 0) 828*dd1104fbSMichen Chang return (PWU_NOMEM); 829*dd1104fbSMichen Chang spw->sp_lstchg = DAY_NOW_32; 830*dd1104fbSMichen Chang } 831*dd1104fbSMichen Chang } 832*dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i); 833*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_MAX, val); 834*dd1104fbSMichen Chang aging_set = 1; 835*dd1104fbSMichen Chang break; 836*dd1104fbSMichen Chang 8377c478bd9Sstevel@tonic-gate case ATTR_WARN: 838*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 839*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 840*dd1104fbSMichen Chang if (spw->sp_max == -1 && 841*dd1104fbSMichen Chang p->data.val_i != -1 && max_present(p->next) == 0) 842*dd1104fbSMichen Chang return (PWU_AGING_DISABLED); 843*dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i); 844*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_WARNING, val); 845*dd1104fbSMichen Chang break; 846*dd1104fbSMichen Chang 8477c478bd9Sstevel@tonic-gate case ATTR_INACT: 848*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 849*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 850*dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i); 851*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_INACTIVE, val); 852*dd1104fbSMichen Chang break; 853*dd1104fbSMichen Chang 8547c478bd9Sstevel@tonic-gate case ATTR_EXPIRE: 855*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 856*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 857*dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i); 858*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_EXPIRE, val); 859*dd1104fbSMichen Chang break; 860*dd1104fbSMichen Chang 8617c478bd9Sstevel@tonic-gate case ATTR_FLAG: 862*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) 863*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 864*dd1104fbSMichen Chang NUM_TO_STR(val, p->data.val_i); 865*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_FLAG, val); 866*dd1104fbSMichen Chang break; 867*dd1104fbSMichen Chang case ATTR_INCR_FAILED_LOGINS: 868*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) { 869*dd1104fbSMichen Chang rc = PWU_CHANGE_NOT_ALLOWED; 870*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 871*dd1104fbSMichen Chang } 872*dd1104fbSMichen Chang count = (spw->sp_flag & FAILCOUNT_MASK) + 1; 873*dd1104fbSMichen Chang spw->sp_flag &= ~FAILCOUNT_MASK; 874*dd1104fbSMichen Chang spw->sp_flag |= min(FAILCOUNT_MASK, count); 875*dd1104fbSMichen Chang p->data.val_i = count; 876*dd1104fbSMichen Chang NUM_TO_STR(val, spw->sp_flag); 877*dd1104fbSMichen Chang NEW_ATTR(sattrs, sidx, _S_FLAG, val); 878*dd1104fbSMichen Chang break; 879*dd1104fbSMichen Chang case ATTR_RST_FAILED_LOGINS: 880*dd1104fbSMichen Chang if (!ldapbuf->shadow_update_enabled) { 881*dd1104fbSMichen Chang rc = PWU_CHANGE_NOT_ALLOWED; 882*dd1104fbSMichen Chang break; /* not managing passwordAccount */ 883*dd1104fbSMichen Chang } 884*dd1104fbSMichen Chang p->data.val_i = spw->sp_flag & FAILCOUNT_MASK; 885*dd1104fbSMichen Chang spw->sp_flag &= ~FAILCOUNT_MASK; 886*dd1104fbSMichen Chang NUM_TO_STR(val, spw->sp_flag); 887*dd1104fbSMichen 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 894*dd1104fbSMichen Chang /* 895*dd1104fbSMichen Chang * If the ldap client is configured with shadow update enabled, 896*dd1104fbSMichen Chang * then what should the new aging values look like? 897*dd1104fbSMichen Chang * 898*dd1104fbSMichen Chang * There are a number of different conditions 899*dd1104fbSMichen Chang * 900*dd1104fbSMichen Chang * a) aging is already configured: don't touch it 901*dd1104fbSMichen Chang * 902*dd1104fbSMichen Chang * b) disable_aging is set: disable aging 903*dd1104fbSMichen Chang * 904*dd1104fbSMichen Chang * c) aging is not configured: turn on default aging; 905*dd1104fbSMichen Chang * 906*dd1104fbSMichen Chang * b) and c) of course only if aging_needed and !aging_set. 907*dd1104fbSMichen Chang * (i.e., password changed, and aging values not changed) 908*dd1104fbSMichen Chang */ 9097c478bd9Sstevel@tonic-gate 910*dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled && spw != NULL && spw->sp_max <= 0) { 911*dd1104fbSMichen Chang /* a) aging not yet configured */ 912*dd1104fbSMichen Chang if (aging_needed && !aging_set) { 913*dd1104fbSMichen Chang if (disable_aging) { 914*dd1104fbSMichen Chang /* b) turn off aging */ 915*dd1104fbSMichen Chang spw->sp_min = spw->sp_max = spw->sp_warn = -1; 916*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_MIN, -1) < 0) 917*dd1104fbSMichen Chang return (PWU_NOMEM); 918*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_MAX, -1) < 0) 919*dd1104fbSMichen Chang return (PWU_NOMEM); 920*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_WARNING, 921*dd1104fbSMichen Chang -1) < 0) 922*dd1104fbSMichen Chang return (PWU_NOMEM); 923*dd1104fbSMichen Chang } else { 924*dd1104fbSMichen Chang /* c) */ 925*dd1104fbSMichen Chang turn_on_default_aging(spw); 926*dd1104fbSMichen Chang 927*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_MIN, 928*dd1104fbSMichen Chang spw->sp_min) < 0) 929*dd1104fbSMichen Chang return (PWU_NOMEM); 930*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, _S_MAX, 931*dd1104fbSMichen Chang spw->sp_max) < 0) 932*dd1104fbSMichen Chang return (PWU_NOMEM); 933*dd1104fbSMichen Chang if (attr_addmod(sattrs, &sidx, 934*dd1104fbSMichen Chang _S_WARNING, spw->sp_warn) < 0) 935*dd1104fbSMichen Chang return (PWU_NOMEM); 936*dd1104fbSMichen Chang } 937*dd1104fbSMichen Chang } 938*dd1104fbSMichen Chang } 939*dd1104fbSMichen Chang 940*dd1104fbSMichen Chang pattrs[pidx] = NULL; 941*dd1104fbSMichen Chang sattrs[sidx] = NULL; 942*dd1104fbSMichen Chang 943*dd1104fbSMichen 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, 983*dd1104fbSMichen 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) 998*dd1104fbSMichen Chang return (NS_LDAP_MEMORY); /* map to PWU_NOMEM */ 9997c478bd9Sstevel@tonic-gate 1000*dd1104fbSMichen Chang /* for admin shadow update, dn and pwd will be set later in libsldap */ 1001*dd1104fbSMichen 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); 1007*dd1104fbSMichen 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, 1064*dd1104fbSMichen 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 /* 1071*dd1104fbSMichen Chang * if change not allowed due to configuration, indicate so 1072*dd1104fbSMichen Chang * to the caller 1073*dd1104fbSMichen Chang */ 1074*dd1104fbSMichen Chang if (ldaprc == NS_LDAP_CONFIG && 1075*dd1104fbSMichen Chang errorp->status == NS_CONFIG_NOTALLOW) { 1076*dd1104fbSMichen Chang result = NS_LDAP_CONFIG; 1077*dd1104fbSMichen Chang *pwd_status = NS_PASSWD_CHANGE_NOT_ALLOWED; 1078*dd1104fbSMichen Chang goto out; 1079*dd1104fbSMichen Chang } 1080*dd1104fbSMichen Chang 1081*dd1104fbSMichen 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 } 1115*dd1104fbSMichen 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 /* 11327c478bd9Sstevel@tonic-gate * ldap_putpwnam(name, oldpw, dummy, rep, buf) 11337c478bd9Sstevel@tonic-gate * 11347c478bd9Sstevel@tonic-gate * update the LDAP server with the attributes contained in 'buf'. 11357c478bd9Sstevel@tonic-gate * The dummy parameter is a placeholder for NIS+ where the old 11367c478bd9Sstevel@tonic-gate * RPC password is passwd. 11377c478bd9Sstevel@tonic-gate */ 11387c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11397c478bd9Sstevel@tonic-gate int 11407c478bd9Sstevel@tonic-gate ldap_putpwnam(char *name, char *oldpw, char *dummy, 11417c478bd9Sstevel@tonic-gate pwu_repository_t *rep, void *buf) 11427c478bd9Sstevel@tonic-gate { 11437c478bd9Sstevel@tonic-gate int res; 11447c478bd9Sstevel@tonic-gate char *dn; /* dn of user whose attributes we are changing */ 11457c478bd9Sstevel@tonic-gate char *binddn; /* dn of user who is performing the change */ 11467c478bd9Sstevel@tonic-gate ns_ldap_error_t *errorp; 11477c478bd9Sstevel@tonic-gate ldapbuf_t *ldapbuf = (ldapbuf_t *)buf; 1148*dd1104fbSMichen Chang ns_ldap_attr_t **pattrs = ldapbuf->pattrs; 1149*dd1104fbSMichen Chang ns_ldap_attr_t **sattrs = ldapbuf->sattrs; 11507c478bd9Sstevel@tonic-gate struct passwd *pw; 11517c478bd9Sstevel@tonic-gate int pwd_status; 11527c478bd9Sstevel@tonic-gate uid_t uid; 11537c478bd9Sstevel@tonic-gate 11547c478bd9Sstevel@tonic-gate if (strcmp(name, "root") == 0) 11557c478bd9Sstevel@tonic-gate return (PWU_NOT_FOUND); 11567c478bd9Sstevel@tonic-gate 11577c478bd9Sstevel@tonic-gate /* 1158*dd1104fbSMichen Chang * convert name of user whose attributes we are changing 1159*dd1104fbSMichen Chang * to a distinguished name 1160*dd1104fbSMichen Chang */ 1161*dd1104fbSMichen Chang res = __ns_ldap_uid2dn(name, &dn, NULL, &errorp); 1162*dd1104fbSMichen Chang if (res != NS_LDAP_SUCCESS) 1163*dd1104fbSMichen Chang goto out; 1164*dd1104fbSMichen Chang 1165*dd1104fbSMichen Chang /* update shadow via ldap_cachemgr if it is enabled */ 1166*dd1104fbSMichen Chang if (ldapbuf->shadow_update_enabled && 1167*dd1104fbSMichen Chang sattrs != NULL && sattrs[0] != NULL) { 1168*dd1104fbSMichen Chang /* 1169*dd1104fbSMichen Chang * flag NS_LDAP_UPDATE_SHADOW indicates the shadow update 1170*dd1104fbSMichen Chang * should be done via ldap_cachemgr 1171*dd1104fbSMichen Chang */ 1172*dd1104fbSMichen Chang res = ldap_replaceattr(dn, sattrs, NULL, NULL, &pwd_status, 1173*dd1104fbSMichen Chang NS_LDAP_UPDATE_SHADOW); 1174*dd1104fbSMichen Chang goto out; 1175*dd1104fbSMichen Chang } 1176*dd1104fbSMichen Chang 1177*dd1104fbSMichen Chang /* 11787c478bd9Sstevel@tonic-gate * The LDAP server checks whether we are permitted to perform 11797c478bd9Sstevel@tonic-gate * the requested change. We need to send the name of the user 11807c478bd9Sstevel@tonic-gate * who is executing this piece of code, together with his 11817c478bd9Sstevel@tonic-gate * current password to the server. 11827c478bd9Sstevel@tonic-gate * If this is executed by a normal user changing his/her own 11837c478bd9Sstevel@tonic-gate * password, this will simply be the OLD password that is to 11847c478bd9Sstevel@tonic-gate * be changed. 11857c478bd9Sstevel@tonic-gate * Specific case if the user who is executing this piece 11867c478bd9Sstevel@tonic-gate * of code is root. We will then issue the LDAP request 11877c478bd9Sstevel@tonic-gate * with the DN of the user we want to change the passwd of. 11887c478bd9Sstevel@tonic-gate */ 11897c478bd9Sstevel@tonic-gate 11907c478bd9Sstevel@tonic-gate /* 11917c478bd9Sstevel@tonic-gate * create a dn for the user who is executing this code 11927c478bd9Sstevel@tonic-gate */ 11937c478bd9Sstevel@tonic-gate uid = getuid(); 11947c478bd9Sstevel@tonic-gate if (uid == 0) { 11957c478bd9Sstevel@tonic-gate if ((pw = getpwnam_from(name, rep, REP_LDAP)) == NULL) { 11967c478bd9Sstevel@tonic-gate res = NS_LDAP_OP_FAILED; 11977c478bd9Sstevel@tonic-gate goto out; 11987c478bd9Sstevel@tonic-gate } 11997c478bd9Sstevel@tonic-gate } else if ((pw = getpwuid_from(uid, rep, REP_LDAP)) == NULL) { 12007c478bd9Sstevel@tonic-gate /* 12017c478bd9Sstevel@tonic-gate * User executing this code is not known to the LDAP 12027c478bd9Sstevel@tonic-gate * server. This operation is to be denied 12037c478bd9Sstevel@tonic-gate */ 12047c478bd9Sstevel@tonic-gate res = NS_LDAP_OP_FAILED; 12057c478bd9Sstevel@tonic-gate goto out; 12067c478bd9Sstevel@tonic-gate } 12077c478bd9Sstevel@tonic-gate 12087c478bd9Sstevel@tonic-gate res = __ns_ldap_uid2dn(pw->pw_name, &binddn, NULL, &errorp); 12097c478bd9Sstevel@tonic-gate if (res != NS_LDAP_SUCCESS) 12107c478bd9Sstevel@tonic-gate goto out; 12117c478bd9Sstevel@tonic-gate 1212*dd1104fbSMichen Chang if (pattrs && pattrs[0] != NULL) { 1213*dd1104fbSMichen Chang res = ldap_replaceattr(dn, pattrs, binddn, oldpw, 1214*dd1104fbSMichen Chang &pwd_status, 0); 1215*dd1104fbSMichen Chang } else 1216*dd1104fbSMichen Chang res = NS_LDAP_OP_FAILED; 12177c478bd9Sstevel@tonic-gate 12187c478bd9Sstevel@tonic-gate out: 1219*dd1104fbSMichen Chang free_ldapbuf(ldapbuf); 12207c478bd9Sstevel@tonic-gate free(dn); 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate return (ldap_to_pwu_code(res, pwd_status)); 12237c478bd9Sstevel@tonic-gate } 1224