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