1*7c478bd9Sstevel@tonic-gate /* 2*7c478bd9Sstevel@tonic-gate * CDDL HEADER START 3*7c478bd9Sstevel@tonic-gate * 4*7c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*7c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*7c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*7c478bd9Sstevel@tonic-gate * with the License. 8*7c478bd9Sstevel@tonic-gate * 9*7c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*7c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*7c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 12*7c478bd9Sstevel@tonic-gate * and limitations under the License. 13*7c478bd9Sstevel@tonic-gate * 14*7c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*7c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*7c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*7c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*7c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*7c478bd9Sstevel@tonic-gate * 20*7c478bd9Sstevel@tonic-gate * CDDL HEADER END 21*7c478bd9Sstevel@tonic-gate */ 22*7c478bd9Sstevel@tonic-gate /* 23*7c478bd9Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*7c478bd9Sstevel@tonic-gate * Use is subject to license terms. 25*7c478bd9Sstevel@tonic-gate */ 26*7c478bd9Sstevel@tonic-gate 27*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*7c478bd9Sstevel@tonic-gate 29*7c478bd9Sstevel@tonic-gate #include "ldap_headers.h" 30*7c478bd9Sstevel@tonic-gate #include <malloc.h> 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate /* ******************************************************************** */ 33*7c478bd9Sstevel@tonic-gate /* */ 34*7c478bd9Sstevel@tonic-gate /* Utilities Functions */ 35*7c478bd9Sstevel@tonic-gate /* */ 36*7c478bd9Sstevel@tonic-gate /* ******************************************************************** */ 37*7c478bd9Sstevel@tonic-gate 38*7c478bd9Sstevel@tonic-gate /* 39*7c478bd9Sstevel@tonic-gate * __ldap_to_pamerror(): 40*7c478bd9Sstevel@tonic-gate * converts Native LDAP errors to an equivalent PAM error 41*7c478bd9Sstevel@tonic-gate */ 42*7c478bd9Sstevel@tonic-gate int 43*7c478bd9Sstevel@tonic-gate __ldap_to_pamerror(int ldaperror) 44*7c478bd9Sstevel@tonic-gate { 45*7c478bd9Sstevel@tonic-gate switch (ldaperror) { 46*7c478bd9Sstevel@tonic-gate case NS_LDAP_SUCCESS: 47*7c478bd9Sstevel@tonic-gate return (PAM_SUCCESS); 48*7c478bd9Sstevel@tonic-gate 49*7c478bd9Sstevel@tonic-gate case NS_LDAP_OP_FAILED: 50*7c478bd9Sstevel@tonic-gate return (PAM_PERM_DENIED); 51*7c478bd9Sstevel@tonic-gate 52*7c478bd9Sstevel@tonic-gate case NS_LDAP_MEMORY: 53*7c478bd9Sstevel@tonic-gate return (PAM_BUF_ERR); 54*7c478bd9Sstevel@tonic-gate 55*7c478bd9Sstevel@tonic-gate case NS_LDAP_CONFIG: 56*7c478bd9Sstevel@tonic-gate return (PAM_SERVICE_ERR); 57*7c478bd9Sstevel@tonic-gate 58*7c478bd9Sstevel@tonic-gate case NS_LDAP_NOTFOUND: 59*7c478bd9Sstevel@tonic-gate case NS_LDAP_INTERNAL: 60*7c478bd9Sstevel@tonic-gate case NS_LDAP_PARTIAL: 61*7c478bd9Sstevel@tonic-gate case NS_LDAP_INVALID_PARAM: 62*7c478bd9Sstevel@tonic-gate return (PAM_SYSTEM_ERR); 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate default: 65*7c478bd9Sstevel@tonic-gate return (PAM_SYSTEM_ERR); 66*7c478bd9Sstevel@tonic-gate 67*7c478bd9Sstevel@tonic-gate } 68*7c478bd9Sstevel@tonic-gate } 69*7c478bd9Sstevel@tonic-gate 70*7c478bd9Sstevel@tonic-gate /* 71*7c478bd9Sstevel@tonic-gate * authenticate(): 72*7c478bd9Sstevel@tonic-gate * Returns 73*7c478bd9Sstevel@tonic-gate * PAM_SUCCESS if authenticated successfully 74*7c478bd9Sstevel@tonic-gate * PAM_NEW_AUTHTOK_REQD if authenticated but user needs to 75*7c478bd9Sstevel@tonic-gate * change password immediately 76*7c478bd9Sstevel@tonic-gate * PAM_MAXTRIES if authentication fails due to too 77*7c478bd9Sstevel@tonic-gate * many login failures 78*7c478bd9Sstevel@tonic-gate * PAM_AUTHTOK_EXPIRED if user password expired 79*7c478bd9Sstevel@tonic-gate * PAM_PERM_DENIED if fail to authenticate 80*7c478bd9Sstevel@tonic-gate * PAM_AUTH_ERR other errors 81*7c478bd9Sstevel@tonic-gate * 82*7c478bd9Sstevel@tonic-gate * Also output the second-until-expired data if authenticated 83*7c478bd9Sstevel@tonic-gate * but the password is about to expire. 84*7c478bd9Sstevel@tonic-gate * Authentication is checked by calling __ns_ldap_auth. 85*7c478bd9Sstevel@tonic-gate */ 86*7c478bd9Sstevel@tonic-gate int 87*7c478bd9Sstevel@tonic-gate authenticate(ns_cred_t **credpp, char *usrname, char *pwd, 88*7c478bd9Sstevel@tonic-gate int *sec_until_expired) 89*7c478bd9Sstevel@tonic-gate { 90*7c478bd9Sstevel@tonic-gate int result = PAM_AUTH_ERR; 91*7c478bd9Sstevel@tonic-gate int ldaprc; 92*7c478bd9Sstevel@tonic-gate int authstried = 0; 93*7c478bd9Sstevel@tonic-gate char *binddn = NULL; 94*7c478bd9Sstevel@tonic-gate char **certpath = NULL; 95*7c478bd9Sstevel@tonic-gate ns_auth_t **app; 96*7c478bd9Sstevel@tonic-gate ns_auth_t **authpp = NULL; 97*7c478bd9Sstevel@tonic-gate ns_auth_t *authp = NULL; 98*7c478bd9Sstevel@tonic-gate ns_cred_t *credp; 99*7c478bd9Sstevel@tonic-gate ns_ldap_error_t *errorp = NULL; 100*7c478bd9Sstevel@tonic-gate 101*7c478bd9Sstevel@tonic-gate if ((credp = (ns_cred_t *)calloc(1, sizeof (ns_cred_t))) == NULL) 102*7c478bd9Sstevel@tonic-gate return (PAM_BUF_ERR); 103*7c478bd9Sstevel@tonic-gate 104*7c478bd9Sstevel@tonic-gate /* Fill in the user name and password */ 105*7c478bd9Sstevel@tonic-gate if ((usrname == NULL) || (pwd == NULL) || (usrname[0] == '\0') || 106*7c478bd9Sstevel@tonic-gate (pwd[0] == '\0')) 107*7c478bd9Sstevel@tonic-gate goto out; 108*7c478bd9Sstevel@tonic-gate 109*7c478bd9Sstevel@tonic-gate ldaprc = __ns_ldap_uid2dn(usrname, &binddn, NULL, &errorp); 110*7c478bd9Sstevel@tonic-gate if ((result = __ldap_to_pamerror(ldaprc)) != PAM_SUCCESS) 111*7c478bd9Sstevel@tonic-gate goto out; 112*7c478bd9Sstevel@tonic-gate 113*7c478bd9Sstevel@tonic-gate credp->cred.unix_cred.userID = strdup(binddn); 114*7c478bd9Sstevel@tonic-gate credp->cred.unix_cred.passwd = strdup(pwd); 115*7c478bd9Sstevel@tonic-gate if ((credp->cred.unix_cred.userID == NULL) || 116*7c478bd9Sstevel@tonic-gate (credp->cred.unix_cred.passwd == NULL)) { 117*7c478bd9Sstevel@tonic-gate result = PAM_BUF_ERR; 118*7c478bd9Sstevel@tonic-gate goto out; 119*7c478bd9Sstevel@tonic-gate } 120*7c478bd9Sstevel@tonic-gate 121*7c478bd9Sstevel@tonic-gate /* get host certificate path, if one is configured */ 122*7c478bd9Sstevel@tonic-gate ldaprc = __ns_ldap_getParam(NS_LDAP_HOST_CERTPATH_P, 123*7c478bd9Sstevel@tonic-gate (void ***)&certpath, &errorp); 124*7c478bd9Sstevel@tonic-gate if ((result = __ldap_to_pamerror(ldaprc)) != PAM_SUCCESS) 125*7c478bd9Sstevel@tonic-gate goto out; 126*7c478bd9Sstevel@tonic-gate if (certpath && *certpath) 127*7c478bd9Sstevel@tonic-gate credp->hostcertpath = *certpath; 128*7c478bd9Sstevel@tonic-gate 129*7c478bd9Sstevel@tonic-gate /* Load the service specific authentication method */ 130*7c478bd9Sstevel@tonic-gate ldaprc = __ns_ldap_getServiceAuthMethods("pam_ldap", &authpp, &errorp); 131*7c478bd9Sstevel@tonic-gate if ((result = __ldap_to_pamerror(ldaprc)) != PAM_SUCCESS) 132*7c478bd9Sstevel@tonic-gate goto out; 133*7c478bd9Sstevel@tonic-gate 134*7c478bd9Sstevel@tonic-gate /* 135*7c478bd9Sstevel@tonic-gate * if authpp is null, there is no serviceAuthenticationMethod 136*7c478bd9Sstevel@tonic-gate * try default authenticationMethod 137*7c478bd9Sstevel@tonic-gate */ 138*7c478bd9Sstevel@tonic-gate if (authpp == NULL) { 139*7c478bd9Sstevel@tonic-gate ldaprc = __ns_ldap_getParam(NS_LDAP_AUTH_P, (void ***)&authpp, 140*7c478bd9Sstevel@tonic-gate &errorp); 141*7c478bd9Sstevel@tonic-gate if ((result = __ldap_to_pamerror(ldaprc)) != PAM_SUCCESS) 142*7c478bd9Sstevel@tonic-gate goto out; 143*7c478bd9Sstevel@tonic-gate } 144*7c478bd9Sstevel@tonic-gate 145*7c478bd9Sstevel@tonic-gate /* 146*7c478bd9Sstevel@tonic-gate * if authpp is still null, then can not authenticate, syslog 147*7c478bd9Sstevel@tonic-gate * error message and return error 148*7c478bd9Sstevel@tonic-gate */ 149*7c478bd9Sstevel@tonic-gate if (authpp == NULL) { 150*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 151*7c478bd9Sstevel@tonic-gate "pam_ldap: no authentication method configured"); 152*7c478bd9Sstevel@tonic-gate result = PAM_AUTH_ERR; 153*7c478bd9Sstevel@tonic-gate goto out; 154*7c478bd9Sstevel@tonic-gate } 155*7c478bd9Sstevel@tonic-gate 156*7c478bd9Sstevel@tonic-gate /* 157*7c478bd9Sstevel@tonic-gate * Walk the array and try all authentication methods in order except 158*7c478bd9Sstevel@tonic-gate * for "none". 159*7c478bd9Sstevel@tonic-gate */ 160*7c478bd9Sstevel@tonic-gate for (app = authpp; *app; app++) { 161*7c478bd9Sstevel@tonic-gate authp = *app; 162*7c478bd9Sstevel@tonic-gate /* what about disabling other mechanisms? "tls:sasl/EXTERNAL" */ 163*7c478bd9Sstevel@tonic-gate if (authp->type == NS_LDAP_AUTH_NONE) 164*7c478bd9Sstevel@tonic-gate continue; 165*7c478bd9Sstevel@tonic-gate authstried++; 166*7c478bd9Sstevel@tonic-gate credp->auth.type = authp->type; 167*7c478bd9Sstevel@tonic-gate credp->auth.tlstype = authp->tlstype; 168*7c478bd9Sstevel@tonic-gate credp->auth.saslmech = authp->saslmech; 169*7c478bd9Sstevel@tonic-gate credp->auth.saslopt = authp->saslopt; 170*7c478bd9Sstevel@tonic-gate ldaprc = __ns_ldap_auth(credp, 0, &errorp, NULL, NULL); 171*7c478bd9Sstevel@tonic-gate 172*7c478bd9Sstevel@tonic-gate /* 173*7c478bd9Sstevel@tonic-gate * If rc is NS_LDAP_SUCCESS, done. If not, 174*7c478bd9Sstevel@tonic-gate * check rc and error info to see if 175*7c478bd9Sstevel@tonic-gate * there's any password management data. 176*7c478bd9Sstevel@tonic-gate * If yes, set appropriate PAM result code 177*7c478bd9Sstevel@tonic-gate * and exit. 178*7c478bd9Sstevel@tonic-gate */ 179*7c478bd9Sstevel@tonic-gate if (ldaprc == NS_LDAP_SUCCESS) { 180*7c478bd9Sstevel@tonic-gate /* 181*7c478bd9Sstevel@tonic-gate * authenticated and no 182*7c478bd9Sstevel@tonic-gate * password management info, done. 183*7c478bd9Sstevel@tonic-gate */ 184*7c478bd9Sstevel@tonic-gate result = PAM_SUCCESS; 185*7c478bd9Sstevel@tonic-gate goto out; 186*7c478bd9Sstevel@tonic-gate } else if (ldaprc == NS_LDAP_SUCCESS_WITH_INFO) { 187*7c478bd9Sstevel@tonic-gate /* 188*7c478bd9Sstevel@tonic-gate * authenticated but need to deal with 189*7c478bd9Sstevel@tonic-gate * password management info 190*7c478bd9Sstevel@tonic-gate */ 191*7c478bd9Sstevel@tonic-gate result = PAM_SUCCESS; 192*7c478bd9Sstevel@tonic-gate 193*7c478bd9Sstevel@tonic-gate /* 194*7c478bd9Sstevel@tonic-gate * clear sec_until_expired just in case 195*7c478bd9Sstevel@tonic-gate * there's no error info 196*7c478bd9Sstevel@tonic-gate */ 197*7c478bd9Sstevel@tonic-gate if (sec_until_expired) 198*7c478bd9Sstevel@tonic-gate *sec_until_expired = 0; 199*7c478bd9Sstevel@tonic-gate 200*7c478bd9Sstevel@tonic-gate if (errorp) { 201*7c478bd9Sstevel@tonic-gate if (errorp->pwd_mgmt.status == 202*7c478bd9Sstevel@tonic-gate NS_PASSWD_ABOUT_TO_EXPIRE) { 203*7c478bd9Sstevel@tonic-gate /* 204*7c478bd9Sstevel@tonic-gate * password about to expire; 205*7c478bd9Sstevel@tonic-gate * retrieve "seconds until expired" 206*7c478bd9Sstevel@tonic-gate */ 207*7c478bd9Sstevel@tonic-gate if (sec_until_expired) 208*7c478bd9Sstevel@tonic-gate *sec_until_expired = 209*7c478bd9Sstevel@tonic-gate errorp-> 210*7c478bd9Sstevel@tonic-gate pwd_mgmt.sec_until_expired; 211*7c478bd9Sstevel@tonic-gate } else if (errorp->pwd_mgmt.status == 212*7c478bd9Sstevel@tonic-gate NS_PASSWD_CHANGE_NEEDED) 213*7c478bd9Sstevel@tonic-gate /* 214*7c478bd9Sstevel@tonic-gate * indicate that passwd need to change 215*7c478bd9Sstevel@tonic-gate * right away 216*7c478bd9Sstevel@tonic-gate */ 217*7c478bd9Sstevel@tonic-gate result = PAM_NEW_AUTHTOK_REQD; 218*7c478bd9Sstevel@tonic-gate 219*7c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 220*7c478bd9Sstevel@tonic-gate } 221*7c478bd9Sstevel@tonic-gate goto out; 222*7c478bd9Sstevel@tonic-gate } else if (ldaprc == NS_LDAP_INTERNAL) { 223*7c478bd9Sstevel@tonic-gate 224*7c478bd9Sstevel@tonic-gate if (errorp) { 225*7c478bd9Sstevel@tonic-gate /* 226*7c478bd9Sstevel@tonic-gate * If error due to password policy, set 227*7c478bd9Sstevel@tonic-gate * appropriate PAM result code and exit. 228*7c478bd9Sstevel@tonic-gate */ 229*7c478bd9Sstevel@tonic-gate if (errorp->pwd_mgmt.status == 230*7c478bd9Sstevel@tonic-gate NS_PASSWD_RETRY_EXCEEDED) 231*7c478bd9Sstevel@tonic-gate result = PAM_MAXTRIES; 232*7c478bd9Sstevel@tonic-gate else if (errorp->pwd_mgmt.status == 233*7c478bd9Sstevel@tonic-gate NS_PASSWD_EXPIRED) 234*7c478bd9Sstevel@tonic-gate result = PAM_AUTHTOK_EXPIRED; 235*7c478bd9Sstevel@tonic-gate else { 236*7c478bd9Sstevel@tonic-gate /* 237*7c478bd9Sstevel@tonic-gate * If invalid credential, 238*7c478bd9Sstevel@tonic-gate * return PAM_AUTH_ERR. 239*7c478bd9Sstevel@tonic-gate */ 240*7c478bd9Sstevel@tonic-gate if (errorp->status == 241*7c478bd9Sstevel@tonic-gate LDAP_INVALID_CREDENTIALS) 242*7c478bd9Sstevel@tonic-gate result = PAM_AUTH_ERR; 243*7c478bd9Sstevel@tonic-gate } 244*7c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 245*7c478bd9Sstevel@tonic-gate goto out; 246*7c478bd9Sstevel@tonic-gate } 247*7c478bd9Sstevel@tonic-gate } 248*7c478bd9Sstevel@tonic-gate 249*7c478bd9Sstevel@tonic-gate /* done with the error info, clean it up */ 250*7c478bd9Sstevel@tonic-gate if (errorp) 251*7c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 252*7c478bd9Sstevel@tonic-gate } 253*7c478bd9Sstevel@tonic-gate if (authstried == 0) { 254*7c478bd9Sstevel@tonic-gate syslog(LOG_ERR, 255*7c478bd9Sstevel@tonic-gate "pam_ldap: no legal authentication method configured"); 256*7c478bd9Sstevel@tonic-gate result = PAM_AUTH_ERR; 257*7c478bd9Sstevel@tonic-gate goto out; 258*7c478bd9Sstevel@tonic-gate } 259*7c478bd9Sstevel@tonic-gate result = PAM_PERM_DENIED; 260*7c478bd9Sstevel@tonic-gate 261*7c478bd9Sstevel@tonic-gate out: 262*7c478bd9Sstevel@tonic-gate if (binddn) 263*7c478bd9Sstevel@tonic-gate free(binddn); 264*7c478bd9Sstevel@tonic-gate 265*7c478bd9Sstevel@tonic-gate if (credp && (result == PAM_SUCCESS || 266*7c478bd9Sstevel@tonic-gate result == PAM_NEW_AUTHTOK_REQD)) 267*7c478bd9Sstevel@tonic-gate if (credpp) 268*7c478bd9Sstevel@tonic-gate *credpp = credp; 269*7c478bd9Sstevel@tonic-gate else 270*7c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeCred(&credp); 271*7c478bd9Sstevel@tonic-gate 272*7c478bd9Sstevel@tonic-gate if (authpp) 273*7c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeParam((void ***)&authpp); 274*7c478bd9Sstevel@tonic-gate 275*7c478bd9Sstevel@tonic-gate if (errorp) 276*7c478bd9Sstevel@tonic-gate (void) __ns_ldap_freeError(&errorp); 277*7c478bd9Sstevel@tonic-gate 278*7c478bd9Sstevel@tonic-gate return (result); 279*7c478bd9Sstevel@tonic-gate } 280