GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldapd/auth.c Lines: 0 226 0.0 %
Date: 2017-11-13 Branches: 0 185 0.0 %

Line Branch Exec Source
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