xref: /openbsd-src/usr.sbin/ldapd/auth.c (revision 9e1f3787a0070ae02fb0e5526da8da40ad0cd60f)
1*9e1f3787Smartijn /*	$OpenBSD: auth.c,v 1.15 2022/06/29 09:10:13 martijn Exp $ */
25d465952Smartinh 
35d465952Smartinh /*
45d465952Smartinh  * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
55d465952Smartinh  *
65d465952Smartinh  * Permission to use, copy, modify, and distribute this software for any
75d465952Smartinh  * purpose with or without fee is hereby granted, provided that the above
85d465952Smartinh  * copyright notice and this permission notice appear in all copies.
95d465952Smartinh  *
105d465952Smartinh  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
115d465952Smartinh  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
125d465952Smartinh  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
135d465952Smartinh  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
145d465952Smartinh  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
155d465952Smartinh  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
165d465952Smartinh  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
175d465952Smartinh  */
185d465952Smartinh 
195d465952Smartinh #include <sys/types.h>
205d465952Smartinh #include <sys/queue.h>
215d465952Smartinh #include <netinet/in.h>
225d465952Smartinh 
23a9ac9ba1Smartinh #include <errno.h>
245d465952Smartinh #include <openssl/sha.h>
255d465952Smartinh #include <pwd.h>
265d465952Smartinh #include <resolv.h>		/* for b64_pton */
275d465952Smartinh #include <stdlib.h>
285d465952Smartinh #include <string.h>
295d465952Smartinh #include <unistd.h>
305d465952Smartinh 
315d465952Smartinh #include "ldapd.h"
32fdd30f56Sbenno #include "log.h"
335d465952Smartinh 
345d465952Smartinh static int
aci_matches(struct aci * aci,struct conn * conn,struct namespace * ns,char * dn,int rights,char * attr,enum scope scope)355d465952Smartinh aci_matches(struct aci *aci, struct conn *conn, struct namespace *ns,
36841a002bSreyk     char *dn, int rights, char *attr, enum scope scope)
375d465952Smartinh {
385d465952Smartinh 	struct btval	 key;
395d465952Smartinh 
405d465952Smartinh 	if ((rights & aci->rights) != rights)
415d465952Smartinh 		return 0;
425d465952Smartinh 
435d465952Smartinh 	if (dn == NULL)
445d465952Smartinh 		return 0;
455d465952Smartinh 
465d465952Smartinh 	if (aci->target != NULL) {
475d465952Smartinh 		key.size = strlen(dn);
485d465952Smartinh 		key.data = dn;
495d465952Smartinh 
505d465952Smartinh 		if (scope == LDAP_SCOPE_BASE) {
515d465952Smartinh 			switch (aci->scope) {
525d465952Smartinh 			case LDAP_SCOPE_BASE:
535d465952Smartinh 				if (strcmp(dn, aci->target) != 0)
545d465952Smartinh 					return 0;
555d465952Smartinh 				break;
565d465952Smartinh 			case LDAP_SCOPE_ONELEVEL:
575d465952Smartinh 				if (!is_child_of(&key, aci->target))
585d465952Smartinh 					return 0;
595d465952Smartinh 				break;
605d465952Smartinh 			case LDAP_SCOPE_SUBTREE:
615d465952Smartinh 				if (!has_suffix(&key, aci->target))
625d465952Smartinh 					return 0;
635d465952Smartinh 				break;
645d465952Smartinh 			}
655d465952Smartinh 		} else if (scope == LDAP_SCOPE_ONELEVEL) {
665d465952Smartinh 			switch (aci->scope) {
675d465952Smartinh 			case LDAP_SCOPE_BASE:
685d465952Smartinh 				return 0;
695d465952Smartinh 			case LDAP_SCOPE_ONELEVEL:
705d465952Smartinh 				if (strcmp(dn, aci->target) != 0)
715d465952Smartinh 					return 0;
725d465952Smartinh 				break;
735d465952Smartinh 			case LDAP_SCOPE_SUBTREE:
745d465952Smartinh 				if (!has_suffix(&key, aci->target))
755d465952Smartinh 					return 0;
765d465952Smartinh 				break;
775d465952Smartinh 			}
785d465952Smartinh 		} else if (scope == LDAP_SCOPE_SUBTREE) {
795d465952Smartinh 			switch (aci->scope) {
805d465952Smartinh 			case LDAP_SCOPE_BASE:
815d465952Smartinh 			case LDAP_SCOPE_ONELEVEL:
825d465952Smartinh 				return 0;
835d465952Smartinh 			case LDAP_SCOPE_SUBTREE:
845d465952Smartinh 				if (!has_suffix(&key, aci->target))
855d465952Smartinh 					return 0;
865d465952Smartinh 				break;
875d465952Smartinh 			}
885d465952Smartinh 		}
895d465952Smartinh 	}
905d465952Smartinh 
915d465952Smartinh 	if (aci->subject != NULL) {
925d465952Smartinh 		if (conn->binddn == NULL)
935d465952Smartinh 			return 0;
945d465952Smartinh 		if (strcmp(aci->subject, "@") == 0) {
955d465952Smartinh 			if (strcmp(dn, conn->binddn) != 0)
965d465952Smartinh 				return 0;
975d465952Smartinh 		} else if (strcmp(aci->subject, conn->binddn) != 0)
985d465952Smartinh 			return 0;
995d465952Smartinh 	}
1005d465952Smartinh 
101841a002bSreyk 	if (aci->attribute != NULL) {
102841a002bSreyk 		if (attr == NULL)
103841a002bSreyk 			return 0;
104841a002bSreyk 		if (strcasecmp(aci->attribute, attr) != 0)
105841a002bSreyk 			return 0;
106841a002bSreyk 	}
107841a002bSreyk 
1085d465952Smartinh 	return 1;
1095d465952Smartinh }
1105d465952Smartinh 
1115d465952Smartinh /* Returns true (1) if conn is authorized for op on dn in namespace.
1125d465952Smartinh  */
1135d465952Smartinh int
authorized(struct conn * conn,struct namespace * ns,int rights,char * dn,char * attr,int scope)1145d465952Smartinh authorized(struct conn *conn, struct namespace *ns, int rights, char *dn,
115841a002bSreyk     char *attr, int scope)
1165d465952Smartinh {
1175d465952Smartinh 	struct aci	*aci;
1185d465952Smartinh 	int		 type = ACI_ALLOW;
1195d465952Smartinh 
1205d465952Smartinh 	/* Root DN is always allowed. */
1213cf00f2aSmartinh 	if (conn->binddn != NULL) {
1223cf00f2aSmartinh 		if (conf->rootdn != NULL &&
1233cf00f2aSmartinh 		    strcasecmp(conn->binddn, conf->rootdn) == 0)
1245d465952Smartinh 			return 1;
1253cf00f2aSmartinh 		if (ns != NULL && ns->rootdn != NULL &&
1263cf00f2aSmartinh 		    strcasecmp(conn->binddn, ns->rootdn) == 0)
1273cf00f2aSmartinh 			return 1;
1283cf00f2aSmartinh 	}
1295d465952Smartinh 
1305d465952Smartinh 	/* Default to deny for write access. */
1315d465952Smartinh 	if ((rights & (ACI_WRITE | ACI_CREATE)) != 0)
1325d465952Smartinh 		type = ACI_DENY;
1335d465952Smartinh 
134841a002bSreyk 	log_debug("requesting %02X access to %s%s%s by %s, in namespace %s",
1355d465952Smartinh 	    rights,
1363b4314efSdaniel 	    dn ? dn : "any",
137841a002bSreyk 	    attr ? " attribute " : "",
138841a002bSreyk 	    attr ? attr : "",
1393b4314efSdaniel 	    conn->binddn ? conn->binddn : "any",
1405d465952Smartinh 	    ns ? ns->suffix : "global");
1415d465952Smartinh 
1425d465952Smartinh 	SIMPLEQ_FOREACH(aci, &conf->acl, entry) {
143841a002bSreyk 		if (aci_matches(aci, conn, ns, dn, rights,
144841a002bSreyk 		    attr, scope)) {
1455d465952Smartinh 			type = aci->type;
146841a002bSreyk 			log_debug("%s by: %s %02X access to %s%s%s by %s",
1475d465952Smartinh 			    type == ACI_ALLOW ? "allowed" : "denied",
1485d465952Smartinh 			    aci->type == ACI_ALLOW ? "allow" : "deny",
1495d465952Smartinh 			    aci->rights,
1503b4314efSdaniel 			    aci->target ? aci->target : "any",
151841a002bSreyk 			    aci->attribute ? " attribute " : "",
152841a002bSreyk 			    aci->attribute ? aci->attribute : "",
1533b4314efSdaniel 			    aci->subject ? aci->subject : "any");
1545d465952Smartinh 		}
1555d465952Smartinh 	}
1565d465952Smartinh 
1575d465952Smartinh 	if (ns != NULL) {
1585d465952Smartinh 		SIMPLEQ_FOREACH(aci, &ns->acl, entry) {
159841a002bSreyk 			if (aci_matches(aci, conn, ns, dn, rights,
160841a002bSreyk 			    attr, scope)) {
1615d465952Smartinh 				type = aci->type;
162841a002bSreyk 				log_debug("%s by: %s %02X access to %s%s%s by %s",
1635d465952Smartinh 				    type == ACI_ALLOW ? "allowed" : "denied",
1645d465952Smartinh 				    aci->type == ACI_ALLOW ? "allow" : "deny",
1655d465952Smartinh 				    aci->rights,
1663b4314efSdaniel 				    aci->target ? aci->target : "any",
167841a002bSreyk 				    aci->attribute ? " attribute " : "",
168841a002bSreyk 				    aci->attribute ? aci->attribute : "",
1693b4314efSdaniel 				    aci->subject ? aci->subject : "any");
1705d465952Smartinh 			}
1715d465952Smartinh 		}
1725d465952Smartinh 	}
1735d465952Smartinh 
1745d465952Smartinh 	return type == ACI_ALLOW ? 1 : 0;
1755d465952Smartinh }
1765d465952Smartinh 
1775d465952Smartinh static int
send_auth_request(struct request * req,const char * username,const char * password)178e0e29ca6Smartinh send_auth_request(struct request *req, const char *username,
179e0e29ca6Smartinh     const char *password)
1805d465952Smartinh {
181e0e29ca6Smartinh 	struct auth_req	 auth_req;
182e0e29ca6Smartinh 
18337f4b933Smmcc 	memset(&auth_req, 0, sizeof(auth_req));
184e0e29ca6Smartinh 	if (strlcpy(auth_req.name, username,
185e0e29ca6Smartinh 	    sizeof(auth_req.name)) >= sizeof(auth_req.name))
186e0e29ca6Smartinh 		goto fail;
187e0e29ca6Smartinh 	if (strlcpy(auth_req.password, password,
188e0e29ca6Smartinh 	    sizeof(auth_req.password)) >= sizeof(auth_req.password))
189e0e29ca6Smartinh 		goto fail;
190e0e29ca6Smartinh 	auth_req.fd = req->conn->fd;
191e0e29ca6Smartinh 	auth_req.msgid = req->msgid;
192e0e29ca6Smartinh 
193e0e29ca6Smartinh 	if (imsgev_compose(iev_ldapd, IMSG_LDAPD_AUTH, 0, 0, -1, &auth_req,
194e0e29ca6Smartinh 	    sizeof(auth_req)) == -1)
195e0e29ca6Smartinh 		goto fail;
196e0e29ca6Smartinh 
197e0e29ca6Smartinh 	req->conn->bind_req = req;
198e0e29ca6Smartinh 	return 0;
199e0e29ca6Smartinh 
200e0e29ca6Smartinh fail:
20137f4b933Smmcc 	memset(&auth_req, 0, sizeof(auth_req));
202e0e29ca6Smartinh 	return -1;
203e0e29ca6Smartinh }
204e0e29ca6Smartinh 
205dff8fe1cSmartinh /*
206dff8fe1cSmartinh  * Check password. Returns 1 if password matches, 2 if password matching
207dff8fe1cSmartinh  * is in progress, 0 on mismatch and -1 on error.
208dff8fe1cSmartinh  */
209e0e29ca6Smartinh static int
check_password(struct request * req,const char * stored_passwd,const char * passwd)210e0e29ca6Smartinh check_password(struct request *req, const char *stored_passwd,
211e0e29ca6Smartinh     const char *passwd)
212e0e29ca6Smartinh {
213e0e29ca6Smartinh 	unsigned char	 tmp[128];
214e0e29ca6Smartinh 	unsigned char	 md[SHA_DIGEST_LENGTH];
2155d465952Smartinh 	char		*encpw;
2165d465952Smartinh 	unsigned char	*salt;
2175d465952Smartinh 	SHA_CTX		 ctx;
218e0e29ca6Smartinh 	int		 sz;
2195d465952Smartinh 
2203cf00f2aSmartinh 	if (stored_passwd == NULL)
2213cf00f2aSmartinh 		return -1;
2223cf00f2aSmartinh 
223*9e1f3787Smartijn 	if (strncasecmp(stored_passwd, "{SHA}", 5) == 0) {
2245d465952Smartinh 		sz = b64_pton(stored_passwd + 5, tmp, sizeof(tmp));
2255d465952Smartinh 		if (sz != SHA_DIGEST_LENGTH)
226e0e29ca6Smartinh 			return (-1);
2275d465952Smartinh 		SHA1_Init(&ctx);
2285d465952Smartinh 		SHA1_Update(&ctx, passwd, strlen(passwd));
2295d465952Smartinh 		SHA1_Final(md, &ctx);
230dff8fe1cSmartinh 		return (bcmp(md, tmp, SHA_DIGEST_LENGTH) == 0 ? 1 : 0);
231*9e1f3787Smartijn 	} else if (strncasecmp(stored_passwd, "{SSHA}", 6) == 0) {
2325d465952Smartinh 		sz = b64_pton(stored_passwd + 6, tmp, sizeof(tmp));
2335d465952Smartinh 		if (sz <= SHA_DIGEST_LENGTH)
234e0e29ca6Smartinh 			return (-1);
2355d465952Smartinh 		salt = tmp + SHA_DIGEST_LENGTH;
2365d465952Smartinh 		SHA1_Init(&ctx);
2375d465952Smartinh 		SHA1_Update(&ctx, passwd, strlen(passwd));
2385d465952Smartinh 		SHA1_Update(&ctx, salt, sz - SHA_DIGEST_LENGTH);
2395d465952Smartinh 		SHA1_Final(md, &ctx);
240dff8fe1cSmartinh 		return (bcmp(md, tmp, SHA_DIGEST_LENGTH) == 0 ? 1 : 0);
241*9e1f3787Smartijn 	} else if (strncasecmp(stored_passwd, "{CRYPT}", 7) == 0) {
2425d465952Smartinh 		encpw = crypt(passwd, stored_passwd + 7);
2435d465952Smartinh 		if (encpw == NULL)
244e0e29ca6Smartinh 			return (-1);
245e0e29ca6Smartinh 		return (strcmp(encpw, stored_passwd + 7) == 0 ? 1 : 0);
246*9e1f3787Smartijn 	} else if (strncasecmp(stored_passwd, "{BSDAUTH}", 9) == 0) {
247e0e29ca6Smartinh 		if (send_auth_request(req, stored_passwd + 9, passwd) == -1)
248e0e29ca6Smartinh 			return (-1);
249e0e29ca6Smartinh 		return 2;	/* Operation in progress. */
250e0e29ca6Smartinh 	} else
251e0e29ca6Smartinh 		return (strcmp(stored_passwd, passwd) == 0 ? 1 : 0);
2525d465952Smartinh }
2535d465952Smartinh 
2545d465952Smartinh static int
ldap_auth_sasl(struct request * req,char * binddn,struct ber_element * params)2555d465952Smartinh ldap_auth_sasl(struct request *req, char *binddn, struct ber_element *params)
2565d465952Smartinh {
2575d465952Smartinh 	char			*method;
2585d465952Smartinh 	char			*authzid, *authcid, *password;
2595d465952Smartinh 	char			*creds;
260e0e29ca6Smartinh 	size_t			 len;
2615d465952Smartinh 
262696b5899Stb 	if (ober_scanf_elements(params, "{sx", &method, &creds, &len) != 0)
2635d465952Smartinh 		return LDAP_PROTOCOL_ERROR;
2645d465952Smartinh 
2655d465952Smartinh 	if (strcmp(method, "PLAIN") != 0)
2665d465952Smartinh 		return LDAP_STRONG_AUTH_NOT_SUPPORTED;
2675d465952Smartinh 
2685d465952Smartinh 	if ((req->conn->s_flags & F_SECURE) == 0) {
2695d465952Smartinh 		log_info("refusing plain sasl bind on insecure connection");
2705d465952Smartinh 		return LDAP_CONFIDENTIALITY_REQUIRED;
2715d465952Smartinh 	}
2725d465952Smartinh 
2735d465952Smartinh 	authzid = creds;
2745d465952Smartinh 	authcid = memchr(creds, '\0', len);
2755d465952Smartinh 	if (authcid == NULL || authcid + 2 >= creds + len)
2765d465952Smartinh 		return LDAP_PROTOCOL_ERROR;
2775d465952Smartinh 	authcid++;
2785d465952Smartinh 	password = memchr(authcid, '\0', len - (authcid - creds));
2795d465952Smartinh 	if (password == NULL || password + 2 >= creds + len)
2805d465952Smartinh 		return LDAP_PROTOCOL_ERROR;
2815d465952Smartinh 	password++;
2825d465952Smartinh 
2835d465952Smartinh 	log_debug("sasl authorization id = [%s]", authzid);
2845d465952Smartinh 	log_debug("sasl authentication id = [%s]", authcid);
2855d465952Smartinh 
286e0e29ca6Smartinh 	if (send_auth_request(req, authcid, password) != 0)
2875d465952Smartinh 		return LDAP_OPERATIONS_ERROR;
2885d465952Smartinh 
28902cddd88Smartinh 	free(req->conn->binddn);
29002cddd88Smartinh 	req->conn->binddn = NULL;
29102cddd88Smartinh 	if ((req->conn->pending_binddn = strdup(authcid)) == NULL)
29202cddd88Smartinh 		return LDAP_OTHER;
29302cddd88Smartinh 
2945d465952Smartinh 	return LDAP_SUCCESS;
2955d465952Smartinh }
2965d465952Smartinh 
2975d465952Smartinh static int
ldap_auth_simple(struct request * req,char * binddn,struct ber_element * auth)2985d465952Smartinh ldap_auth_simple(struct request *req, char *binddn, struct ber_element *auth)
2995d465952Smartinh {
300dff8fe1cSmartinh 	int			 pwret = 0;
3015d465952Smartinh 	char			*password;
3025d465952Smartinh 	char			*user_password;
3035d465952Smartinh 	struct namespace	*ns;
3045d465952Smartinh 	struct ber_element	*elm = NULL, *pw = NULL;
3055d465952Smartinh 
3065d465952Smartinh 	if (*binddn == '\0') {
3075d465952Smartinh 		free(req->conn->binddn);		/* anonymous bind */
3085d465952Smartinh 		req->conn->binddn = NULL;
3095d465952Smartinh 		log_debug("anonymous bind");
3105d465952Smartinh 		return LDAP_SUCCESS;
3115d465952Smartinh 	}
3125d465952Smartinh 
3135d465952Smartinh 	if ((req->conn->s_flags & F_SECURE) == 0) {
3145d465952Smartinh 		log_info("refusing non-anonymous bind on insecure connection");
3155d465952Smartinh 		return LDAP_CONFIDENTIALITY_REQUIRED;
3165d465952Smartinh 	}
3175d465952Smartinh 
318696b5899Stb 	if (ober_scanf_elements(auth, "s", &password) != 0)
3195d465952Smartinh 		return LDAP_PROTOCOL_ERROR;
3205d465952Smartinh 
3215d465952Smartinh 	if (*password == '\0') {
3225d465952Smartinh 		/* Unauthenticated Authentication Mechanism of Simple Bind */
3235d465952Smartinh 		log_debug("refusing unauthenticated bind");
3245d465952Smartinh 		return LDAP_UNWILLING_TO_PERFORM;
3255d465952Smartinh 	}
3265d465952Smartinh 
3273cf00f2aSmartinh 	if (conf->rootdn != NULL && strcmp(conf->rootdn, binddn) == 0) {
328dff8fe1cSmartinh 		pwret = check_password(req, conf->rootpw, password);
3293cf00f2aSmartinh 	} else if ((ns = namespace_lookup_base(binddn, 1)) == NULL) {
3305d465952Smartinh 		return LDAP_INVALID_CREDENTIALS;
3313cf00f2aSmartinh 	} else if (ns->rootdn != NULL && strcmp(ns->rootdn, binddn) == 0) {
332dff8fe1cSmartinh 		pwret = check_password(req, ns->rootpw, password);
33338c09006Smartinh 	} else if (namespace_has_referrals(ns)) {
33438c09006Smartinh 		return LDAP_INVALID_CREDENTIALS;
3355d465952Smartinh 	} else {
3365d465952Smartinh 		if (!authorized(req->conn, ns, ACI_BIND, binddn,
337841a002bSreyk 		    NULL, LDAP_SCOPE_BASE))
3385d465952Smartinh 			return LDAP_INSUFFICIENT_ACCESS;
3395d465952Smartinh 
3400279e526Smartinh 		elm = namespace_get(ns, binddn);
3410279e526Smartinh 		if (elm == NULL && errno == ESTALE) {
342a9ac9ba1Smartinh 			if (namespace_queue_request(ns, req) != 0)
343a9ac9ba1Smartinh 				return LDAP_BUSY;
344a9ac9ba1Smartinh 			return -1;	/* Database is being reopened. */
345a9ac9ba1Smartinh 		}
346a9ac9ba1Smartinh 
3475d465952Smartinh 		if (elm != NULL)
3485d465952Smartinh 			pw = ldap_get_attribute(elm, "userPassword");
3495d465952Smartinh 		if (pw != NULL) {
3505d465952Smartinh 			for (elm = pw->be_next->be_sub; elm;
3515d465952Smartinh 			    elm = elm->be_next) {
352696b5899Stb 				if (ober_get_string(elm, &user_password) != 0)
3535d465952Smartinh 					continue;
354dff8fe1cSmartinh 				pwret = check_password(req, user_password, password);
355dff8fe1cSmartinh 				if (pwret >= 1)
3565d465952Smartinh 					break;
3575d465952Smartinh 			}
3585d465952Smartinh 		}
3595d465952Smartinh 	}
3605d465952Smartinh 
3615d465952Smartinh 	free(req->conn->binddn);
36202cddd88Smartinh 	req->conn->binddn = NULL;
36302cddd88Smartinh 
364dff8fe1cSmartinh 	if (pwret == 1) {
3655d465952Smartinh 		if ((req->conn->binddn = strdup(binddn)) == NULL)
3665d465952Smartinh 			return LDAP_OTHER;
3675d465952Smartinh 		log_debug("successfully authenticated as %s",
3685d465952Smartinh 		    req->conn->binddn);
3695d465952Smartinh 		return LDAP_SUCCESS;
370dff8fe1cSmartinh 	} else if (pwret == 2) {
37102cddd88Smartinh 		if ((req->conn->pending_binddn = strdup(binddn)) == NULL)
37202cddd88Smartinh 			return LDAP_OTHER;
373e0e29ca6Smartinh 		return -LDAP_SASL_BIND_IN_PROGRESS;
374dff8fe1cSmartinh 	} else if (pwret == 0)
3755d465952Smartinh 		return LDAP_INVALID_CREDENTIALS;
376e0e29ca6Smartinh 	else
377e0e29ca6Smartinh 		return LDAP_OPERATIONS_ERROR;
3785d465952Smartinh }
3795d465952Smartinh 
3805d465952Smartinh void
ldap_bind_continue(struct conn * conn,int ok)3815d465952Smartinh ldap_bind_continue(struct conn *conn, int ok)
3825d465952Smartinh {
3835d465952Smartinh 	int			 rc;
3845d465952Smartinh 
38502cddd88Smartinh 	if (ok) {
3865d465952Smartinh 		rc = LDAP_SUCCESS;
38702cddd88Smartinh 		conn->binddn = conn->pending_binddn;
38802cddd88Smartinh 		log_debug("successfully authenticated as %s", conn->binddn);
38902cddd88Smartinh 	} else {
3905d465952Smartinh 		rc = LDAP_INVALID_CREDENTIALS;
39102cddd88Smartinh 		free(conn->pending_binddn);
39202cddd88Smartinh 	}
39302cddd88Smartinh 	conn->pending_binddn = NULL;
3945d465952Smartinh 
3955d465952Smartinh 	ldap_respond(conn->bind_req, rc);
3965d465952Smartinh 	conn->bind_req = NULL;
3975d465952Smartinh }
3985d465952Smartinh 
3995d465952Smartinh int
ldap_bind(struct request * req)4005d465952Smartinh ldap_bind(struct request *req)
4015d465952Smartinh {
4025d465952Smartinh 	int			 rc = LDAP_OTHER;
4035d465952Smartinh 	long long		 ver;
4045d465952Smartinh 	char			*binddn;
4055d465952Smartinh 	struct ber_element	*auth;
4065d465952Smartinh 
4075d465952Smartinh 	++stats.req_bind;
4085d465952Smartinh 
409696b5899Stb 	if (ober_scanf_elements(req->op, "{ise", &ver, &binddn, &auth) != 0) {
4105d465952Smartinh 		rc = LDAP_PROTOCOL_ERROR;
4115d465952Smartinh 		goto done;
4125d465952Smartinh 	}
4135d465952Smartinh 
4145d465952Smartinh 	if (req->conn->bind_req) {
4155d465952Smartinh 		log_debug("aborting bind in progress with msgid %lld",
4165d465952Smartinh 		    req->conn->bind_req->msgid);
4175d465952Smartinh 		request_free(req->conn->bind_req);
4185d465952Smartinh 		req->conn->bind_req = NULL;
4195d465952Smartinh 	}
4205d465952Smartinh 
4215d465952Smartinh 	normalize_dn(binddn);
4225d465952Smartinh 	log_debug("bind dn = %s", binddn);
4235d465952Smartinh 
4245d465952Smartinh 	switch (auth->be_type) {
4255d465952Smartinh 	case LDAP_AUTH_SIMPLE:
426a9ac9ba1Smartinh 		if ((rc = ldap_auth_simple(req, binddn, auth)) < 0)
427a9ac9ba1Smartinh 			return rc;
4285d465952Smartinh 		break;
4295d465952Smartinh 	case LDAP_AUTH_SASL:
4305d465952Smartinh 		if ((rc = ldap_auth_sasl(req, binddn, auth)) == LDAP_SUCCESS)
4315d465952Smartinh 			return LDAP_SUCCESS;
4325d465952Smartinh 		break;
4335d465952Smartinh 	default:
4345d465952Smartinh 		rc = LDAP_STRONG_AUTH_NOT_SUPPORTED;
4355d465952Smartinh 		break;
4365d465952Smartinh 	}
4375d465952Smartinh 
4385d465952Smartinh done:
4395d465952Smartinh 	return ldap_respond(req, rc);
4405d465952Smartinh }
4415d465952Smartinh 
442