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