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