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