xref: /openbsd-src/usr.sbin/ldapd/auth.c (revision 03adc85b7600a1f8f04886b8321c1c1c0c4933d4)
1 /*	$OpenBSD: auth.c,v 1.12 2017/01/20 11:55:08 benno Exp $ */
2 
3 /*
4  * Copyright (c) 2009, 2010 Martin Hedenfalk <martin@bzero.se>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <netinet/in.h>
22 
23 #include <errno.h>
24 #include <openssl/sha.h>
25 #include <pwd.h>
26 #include <resolv.h>		/* for b64_pton */
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "ldapd.h"
32 #include "log.h"
33 
34 static int
35 aci_matches(struct aci *aci, struct conn *conn, struct namespace *ns,
36     char *dn, int rights, enum scope scope)
37 {
38 	struct btval	 key;
39 
40 	if ((rights & aci->rights) != rights)
41 		return 0;
42 
43 	if (dn == NULL)
44 		return 0;
45 
46 	if (aci->target != NULL) {
47 		key.size = strlen(dn);
48 		key.data = dn;
49 
50 		if (scope == LDAP_SCOPE_BASE) {
51 			switch (aci->scope) {
52 			case LDAP_SCOPE_BASE:
53 				if (strcmp(dn, aci->target) != 0)
54 					return 0;
55 				break;
56 			case LDAP_SCOPE_ONELEVEL:
57 				if (!is_child_of(&key, aci->target))
58 					return 0;
59 				break;
60 			case LDAP_SCOPE_SUBTREE:
61 				if (!has_suffix(&key, aci->target))
62 					return 0;
63 				break;
64 			}
65 		} else if (scope == LDAP_SCOPE_ONELEVEL) {
66 			switch (aci->scope) {
67 			case LDAP_SCOPE_BASE:
68 				return 0;
69 			case LDAP_SCOPE_ONELEVEL:
70 				if (strcmp(dn, aci->target) != 0)
71 					return 0;
72 				break;
73 			case LDAP_SCOPE_SUBTREE:
74 				if (!has_suffix(&key, aci->target))
75 					return 0;
76 				break;
77 			}
78 		} else if (scope == LDAP_SCOPE_SUBTREE) {
79 			switch (aci->scope) {
80 			case LDAP_SCOPE_BASE:
81 			case LDAP_SCOPE_ONELEVEL:
82 				return 0;
83 			case LDAP_SCOPE_SUBTREE:
84 				if (!has_suffix(&key, aci->target))
85 					return 0;
86 				break;
87 			}
88 		}
89 	}
90 
91 	if (aci->subject != NULL) {
92 		if (conn->binddn == NULL)
93 			return 0;
94 		if (strcmp(aci->subject, "@") == 0) {
95 			if (strcmp(dn, conn->binddn) != 0)
96 				return 0;
97 		} else if (strcmp(aci->subject, conn->binddn) != 0)
98 			return 0;
99 	}
100 
101 	return 1;
102 }
103 
104 /* Returns true (1) if conn is authorized for op on dn in namespace.
105  */
106 int
107 authorized(struct conn *conn, struct namespace *ns, int rights, char *dn,
108     int scope)
109 {
110 	struct aci	*aci;
111 	int		 type = ACI_ALLOW;
112 
113 	/* Root DN is always allowed. */
114 	if (conn->binddn != NULL) {
115 		if (conf->rootdn != NULL &&
116 		    strcasecmp(conn->binddn, conf->rootdn) == 0)
117 			return 1;
118 		if (ns != NULL && ns->rootdn != NULL &&
119 		    strcasecmp(conn->binddn, ns->rootdn) == 0)
120 			return 1;
121 	}
122 
123 	/* Default to deny for write access. */
124 	if ((rights & (ACI_WRITE | ACI_CREATE)) != 0)
125 		type = ACI_DENY;
126 
127 	log_debug("requesting %02X access to %s by %s, in namespace %s",
128 	    rights,
129 	    dn ? dn : "any",
130 	    conn->binddn ? conn->binddn : "any",
131 	    ns ? ns->suffix : "global");
132 
133 	SIMPLEQ_FOREACH(aci, &conf->acl, entry) {
134 		if (aci_matches(aci, conn, ns, dn, rights, scope)) {
135 			type = aci->type;
136 			log_debug("%s by: %s %02X access to %s by %s",
137 			    type == ACI_ALLOW ? "allowed" : "denied",
138 			    aci->type == ACI_ALLOW ? "allow" : "deny",
139 			    aci->rights,
140 			    aci->target ? aci->target : "any",
141 			    aci->subject ? aci->subject : "any");
142 		}
143 	}
144 
145 	if (ns != NULL) {
146 		SIMPLEQ_FOREACH(aci, &ns->acl, entry) {
147 			if (aci_matches(aci, conn, ns, dn, rights, scope)) {
148 				type = aci->type;
149 				log_debug("%s by: %s %02X access to %s by %s",
150 				    type == ACI_ALLOW ? "allowed" : "denied",
151 				    aci->type == ACI_ALLOW ? "allow" : "deny",
152 				    aci->rights,
153 				    aci->target ? aci->target : "any",
154 				    aci->subject ? aci->subject : "any");
155 			}
156 		}
157 	}
158 
159 	return type == ACI_ALLOW ? 1 : 0;
160 }
161 
162 static int
163 send_auth_request(struct request *req, const char *username,
164     const char *password)
165 {
166 	struct auth_req	 auth_req;
167 
168 	memset(&auth_req, 0, sizeof(auth_req));
169 	if (strlcpy(auth_req.name, username,
170 	    sizeof(auth_req.name)) >= sizeof(auth_req.name))
171 		goto fail;
172 	if (strlcpy(auth_req.password, password,
173 	    sizeof(auth_req.password)) >= sizeof(auth_req.password))
174 		goto fail;
175 	auth_req.fd = req->conn->fd;
176 	auth_req.msgid = req->msgid;
177 
178 	if (imsgev_compose(iev_ldapd, IMSG_LDAPD_AUTH, 0, 0, -1, &auth_req,
179 	    sizeof(auth_req)) == -1)
180 		goto fail;
181 
182 	req->conn->bind_req = req;
183 	return 0;
184 
185 fail:
186 	memset(&auth_req, 0, sizeof(auth_req));
187 	return -1;
188 }
189 
190 /*
191  * Check password. Returns 1 if password matches, 2 if password matching
192  * is in progress, 0 on mismatch and -1 on error.
193  */
194 static int
195 check_password(struct request *req, const char *stored_passwd,
196     const char *passwd)
197 {
198 	unsigned char	 tmp[128];
199 	unsigned char	 md[SHA_DIGEST_LENGTH];
200 	char		*encpw;
201 	unsigned char	*salt;
202 	SHA_CTX		 ctx;
203 	int		 sz;
204 
205 	if (stored_passwd == NULL)
206 		return -1;
207 
208 	if (strncmp(stored_passwd, "{SHA}", 5) == 0) {
209 		sz = b64_pton(stored_passwd + 5, tmp, sizeof(tmp));
210 		if (sz != SHA_DIGEST_LENGTH)
211 			return (-1);
212 		SHA1_Init(&ctx);
213 		SHA1_Update(&ctx, passwd, strlen(passwd));
214 		SHA1_Final(md, &ctx);
215 		return (bcmp(md, tmp, SHA_DIGEST_LENGTH) == 0 ? 1 : 0);
216 	} else if (strncmp(stored_passwd, "{SSHA}", 6) == 0) {
217 		sz = b64_pton(stored_passwd + 6, tmp, sizeof(tmp));
218 		if (sz <= SHA_DIGEST_LENGTH)
219 			return (-1);
220 		salt = tmp + SHA_DIGEST_LENGTH;
221 		SHA1_Init(&ctx);
222 		SHA1_Update(&ctx, passwd, strlen(passwd));
223 		SHA1_Update(&ctx, salt, sz - SHA_DIGEST_LENGTH);
224 		SHA1_Final(md, &ctx);
225 		return (bcmp(md, tmp, SHA_DIGEST_LENGTH) == 0 ? 1 : 0);
226 	} else if (strncmp(stored_passwd, "{CRYPT}", 7) == 0) {
227 		encpw = crypt(passwd, stored_passwd + 7);
228 		if (encpw == NULL)
229 			return (-1);
230 		return (strcmp(encpw, stored_passwd + 7) == 0 ? 1 : 0);
231 	} else if (strncmp(stored_passwd, "{BSDAUTH}", 9) == 0) {
232 		if (send_auth_request(req, stored_passwd + 9, passwd) == -1)
233 			return (-1);
234 		return 2;	/* Operation in progress. */
235 	} else
236 		return (strcmp(stored_passwd, passwd) == 0 ? 1 : 0);
237 }
238 
239 static int
240 ldap_auth_sasl(struct request *req, char *binddn, struct ber_element *params)
241 {
242 	char			*method;
243 	char			*authzid, *authcid, *password;
244 	char			*creds;
245 	size_t			 len;
246 
247 	if (ber_scanf_elements(params, "{sx", &method, &creds, &len) != 0)
248 		return LDAP_PROTOCOL_ERROR;
249 
250 	if (strcmp(method, "PLAIN") != 0)
251 		return LDAP_STRONG_AUTH_NOT_SUPPORTED;
252 
253 	if ((req->conn->s_flags & F_SECURE) == 0) {
254 		log_info("refusing plain sasl bind on insecure connection");
255 		return LDAP_CONFIDENTIALITY_REQUIRED;
256 	}
257 
258 	authzid = creds;
259 	authcid = memchr(creds, '\0', len);
260 	if (authcid == NULL || authcid + 2 >= creds + len)
261 		return LDAP_PROTOCOL_ERROR;
262 	authcid++;
263 	password = memchr(authcid, '\0', len - (authcid - creds));
264 	if (password == NULL || password + 2 >= creds + len)
265 		return LDAP_PROTOCOL_ERROR;
266 	password++;
267 
268 	log_debug("sasl authorization id = [%s]", authzid);
269 	log_debug("sasl authentication id = [%s]", authcid);
270 
271 	if (send_auth_request(req, authcid, password) != 0)
272 		return LDAP_OPERATIONS_ERROR;
273 
274 	free(req->conn->binddn);
275 	req->conn->binddn = NULL;
276 	if ((req->conn->pending_binddn = strdup(authcid)) == NULL)
277 		return LDAP_OTHER;
278 
279 	return LDAP_SUCCESS;
280 }
281 
282 static int
283 ldap_auth_simple(struct request *req, char *binddn, struct ber_element *auth)
284 {
285 	int			 pwret = 0;
286 	char			*password;
287 	char			*user_password;
288 	struct namespace	*ns;
289 	struct ber_element	*elm = NULL, *pw = NULL;
290 
291 	if (*binddn == '\0') {
292 		free(req->conn->binddn);		/* anonymous bind */
293 		req->conn->binddn = NULL;
294 		log_debug("anonymous bind");
295 		return LDAP_SUCCESS;
296 	}
297 
298 	if ((req->conn->s_flags & F_SECURE) == 0) {
299 		log_info("refusing non-anonymous bind on insecure connection");
300 		return LDAP_CONFIDENTIALITY_REQUIRED;
301 	}
302 
303 	if (ber_scanf_elements(auth, "s", &password) != 0)
304 		return LDAP_PROTOCOL_ERROR;
305 
306 	if (*password == '\0') {
307 		/* Unauthenticated Authentication Mechanism of Simple Bind */
308 		log_debug("refusing unauthenticated bind");
309 		return LDAP_UNWILLING_TO_PERFORM;
310 	}
311 
312 	if (conf->rootdn != NULL && strcmp(conf->rootdn, binddn) == 0) {
313 		pwret = check_password(req, conf->rootpw, password);
314 	} else if ((ns = namespace_lookup_base(binddn, 1)) == NULL) {
315 		return LDAP_INVALID_CREDENTIALS;
316 	} else if (ns->rootdn != NULL && strcmp(ns->rootdn, binddn) == 0) {
317 		pwret = check_password(req, ns->rootpw, password);
318 	} else if (namespace_has_referrals(ns)) {
319 		return LDAP_INVALID_CREDENTIALS;
320 	} else {
321 		if (!authorized(req->conn, ns, ACI_BIND, binddn,
322 		    LDAP_SCOPE_BASE))
323 			return LDAP_INSUFFICIENT_ACCESS;
324 
325 		elm = namespace_get(ns, binddn);
326 		if (elm == NULL && errno == ESTALE) {
327 			if (namespace_queue_request(ns, req) != 0)
328 				return LDAP_BUSY;
329 			return -1;	/* Database is being reopened. */
330 		}
331 
332 		if (elm != NULL)
333 			pw = ldap_get_attribute(elm, "userPassword");
334 		if (pw != NULL) {
335 			for (elm = pw->be_next->be_sub; elm;
336 			    elm = elm->be_next) {
337 				if (ber_get_string(elm, &user_password) != 0)
338 					continue;
339 				pwret = check_password(req, user_password, password);
340 				if (pwret >= 1)
341 					break;
342 			}
343 		}
344 	}
345 
346 	free(req->conn->binddn);
347 	req->conn->binddn = NULL;
348 
349 	if (pwret == 1) {
350 		if ((req->conn->binddn = strdup(binddn)) == NULL)
351 			return LDAP_OTHER;
352 		log_debug("successfully authenticated as %s",
353 		    req->conn->binddn);
354 		return LDAP_SUCCESS;
355 	} else if (pwret == 2) {
356 		if ((req->conn->pending_binddn = strdup(binddn)) == NULL)
357 			return LDAP_OTHER;
358 		return -LDAP_SASL_BIND_IN_PROGRESS;
359 	} else if (pwret == 0)
360 		return LDAP_INVALID_CREDENTIALS;
361 	else
362 		return LDAP_OPERATIONS_ERROR;
363 }
364 
365 void
366 ldap_bind_continue(struct conn *conn, int ok)
367 {
368 	int			 rc;
369 
370 	if (ok) {
371 		rc = LDAP_SUCCESS;
372 		conn->binddn = conn->pending_binddn;
373 		log_debug("successfully authenticated as %s", conn->binddn);
374 	} else {
375 		rc = LDAP_INVALID_CREDENTIALS;
376 		free(conn->pending_binddn);
377 	}
378 	conn->pending_binddn = NULL;
379 
380 	ldap_respond(conn->bind_req, rc);
381 	conn->bind_req = NULL;
382 }
383 
384 int
385 ldap_bind(struct request *req)
386 {
387 	int			 rc = LDAP_OTHER;
388 	long long		 ver;
389 	char			*binddn;
390 	struct ber_element	*auth;
391 
392 	++stats.req_bind;
393 
394 	if (ber_scanf_elements(req->op, "{ise", &ver, &binddn, &auth) != 0) {
395 		rc = LDAP_PROTOCOL_ERROR;
396 		goto done;
397 	}
398 
399 	if (req->conn->bind_req) {
400 		log_debug("aborting bind in progress with msgid %lld",
401 		    req->conn->bind_req->msgid);
402 		request_free(req->conn->bind_req);
403 		req->conn->bind_req = NULL;
404 	}
405 
406 	normalize_dn(binddn);
407 	log_debug("bind dn = %s", binddn);
408 
409 	switch (auth->be_type) {
410 	case LDAP_AUTH_SIMPLE:
411 		if ((rc = ldap_auth_simple(req, binddn, auth)) < 0)
412 			return rc;
413 		break;
414 	case LDAP_AUTH_SASL:
415 		if ((rc = ldap_auth_sasl(req, binddn, auth)) == LDAP_SUCCESS)
416 			return LDAP_SUCCESS;
417 		break;
418 	default:
419 		rc = LDAP_STRONG_AUTH_NOT_SUPPORTED;
420 		break;
421 	}
422 
423 done:
424 	return ldap_respond(req, rc);
425 }
426 
427