xref: /titanic_51/usr/src/lib/pam_modules/ldap/ldap_utils.c (revision fd9cb95cbb2f626355a60efb9d02c5f0a33c10e6)
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
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
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