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
__ldap_to_pamerror(int ldaperror)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
authenticate(ns_cred_t ** credpp,const char * usrname,const char * pwd,int * sec_until_expired)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