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