GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/ldapd/modify.c Lines: 0 182 0.0 %
Date: 2017-11-07 Branches: 0 162 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: modify.c,v 1.20 2017/07/28 12:58:52 florian 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
22
#include <assert.h>
23
#include <errno.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include "ldapd.h"
28
#include "log.h"
29
#include "uuid.h"
30
31
int
32
ldap_delete(struct request *req)
33
{
34
	struct btval		 key;
35
	char			*dn;
36
	struct namespace	*ns;
37
	struct referrals	*refs;
38
	struct cursor		*cursor;
39
	int			 rc = LDAP_OTHER;
40
41
	++stats.req_mod;
42
43
	if (ber_scanf_elements(req->op, "s", &dn) != 0)
44
		return ldap_respond(req, LDAP_PROTOCOL_ERROR);
45
46
	normalize_dn(dn);
47
	log_debug("deleting entry %s", dn);
48
49
	if ((ns = namespace_for_base(dn)) == NULL) {
50
		refs = namespace_referrals(dn);
51
		if (refs == NULL)
52
			return ldap_respond(req, LDAP_NAMING_VIOLATION);
53
		else
54
			return ldap_refer(req, dn, NULL, refs);
55
	}
56
57
	if (!authorized(req->conn, ns, ACI_WRITE, dn, LDAP_SCOPE_BASE))
58
		return ldap_respond(req, LDAP_INSUFFICIENT_ACCESS);
59
60
	if (namespace_begin(ns) != 0) {
61
		if (errno == EBUSY) {
62
			if (namespace_queue_request(ns, req) != 0)
63
				return ldap_respond(req, LDAP_BUSY);
64
			return LDAP_BUSY;
65
		}
66
		return ldap_respond(req, LDAP_OTHER);
67
	}
68
69
	/* Check that this is a leaf node by getting a cursor to the DN
70
	 * we're about to delete. If there is a next entry with the DN
71
	 * as suffix (ie, a child node), the DN can't be deleted.
72
	 */
73
	if ((cursor = btree_txn_cursor_open(NULL, ns->data_txn)) == NULL)
74
		goto done;
75
76
	memset(&key, 0, sizeof(key));
77
	key.data = dn;
78
	key.size = strlen(dn);
79
	if (btree_cursor_get(cursor, &key, NULL, BT_CURSOR_EXACT) != 0) {
80
		if (errno == ENOENT)
81
			rc = LDAP_NO_SUCH_OBJECT;
82
		goto done;
83
	}
84
85
	btval_reset(&key);
86
	if (btree_cursor_get(cursor, &key, NULL, BT_NEXT) != 0) {
87
		if (errno != ENOENT)
88
			goto done;
89
	} else if (has_suffix(&key, dn)) {
90
		rc = LDAP_NOT_ALLOWED_ON_NONLEAF;
91
		goto done;
92
	}
93
94
	if (namespace_del(ns, dn) == 0 && namespace_commit(ns) == 0)
95
		rc = LDAP_SUCCESS;
96
97
done:
98
	btree_cursor_close(cursor);
99
	btval_reset(&key);
100
	namespace_abort(ns);
101
	return ldap_respond(req, rc);
102
}
103
104
int
105
ldap_add(struct request *req)
106
{
107
	char			 uuid_str[64];
108
	struct uuid		 uuid;
109
	char			*dn, *s;
110
	struct attr_type	*at;
111
	struct ber_element	*attrs, *attr, *elm, *set = NULL;
112
	struct namespace	*ns;
113
	struct referrals	*refs;
114
	int			 rc;
115
116
	++stats.req_mod;
117
118
	if (ber_scanf_elements(req->op, "{se", &dn, &attrs) != 0)
119
		return ldap_respond(req, LDAP_PROTOCOL_ERROR);
120
121
	normalize_dn(dn);
122
	log_debug("adding entry %s", dn);
123
124
	if (*dn == '\0')
125
		return ldap_respond(req, LDAP_INVALID_DN_SYNTAX);
126
127
	if ((ns = namespace_for_base(dn)) == NULL) {
128
		refs = namespace_referrals(dn);
129
		if (refs == NULL)
130
			return ldap_respond(req, LDAP_NAMING_VIOLATION);
131
		else
132
			return ldap_refer(req, dn, NULL, refs);
133
	}
134
135
	if (!authorized(req->conn, ns, ACI_WRITE, dn, LDAP_SCOPE_BASE))
136
		return ldap_respond(req, LDAP_INSUFFICIENT_ACCESS);
137
138
	/* Check that we're not adding immutable attributes.
139
	 */
140
	for (elm = attrs->be_sub; elm != NULL; elm = elm->be_next) {
141
		attr = elm->be_sub;
142
		if (attr == NULL || ber_get_string(attr, &s) != 0)
143
			return ldap_respond(req, LDAP_PROTOCOL_ERROR);
144
		if (!ns->relax) {
145
			at = lookup_attribute(conf->schema, s);
146
			if (at == NULL) {
147
				log_debug("unknown attribute type %s", s);
148
				return ldap_respond(req,
149
				    LDAP_NO_SUCH_ATTRIBUTE);
150
			}
151
			if (at->immutable) {
152
				log_debug("attempt to add immutable"
153
				    " attribute %s", s);
154
				return ldap_respond(req,
155
				    LDAP_CONSTRAINT_VIOLATION);
156
			}
157
		}
158
	}
159
160
	if (namespace_begin(ns) == -1) {
161
		if (errno == EBUSY) {
162
			if (namespace_queue_request(ns, req) != 0)
163
				return ldap_respond(req, LDAP_BUSY);
164
			return LDAP_BUSY;
165
		}
166
		return ldap_respond(req, LDAP_OTHER);
167
	}
168
169
	/* add operational attributes
170
	 */
171
	if ((set = ber_add_set(NULL)) == NULL)
172
		goto fail;
173
	if (ber_add_string(set, req->conn->binddn ? req->conn->binddn : "") == NULL)
174
		goto fail;
175
	if (ldap_add_attribute(attrs, "creatorsName", set) == NULL)
176
		goto fail;
177
178
	if ((set = ber_add_set(NULL)) == NULL)
179
		goto fail;
180
	if (ber_add_string(set, ldap_now()) == NULL)
181
		goto fail;
182
	if (ldap_add_attribute(attrs, "createTimestamp", set) == NULL)
183
		goto fail;
184
185
	uuid_create(&uuid);
186
	uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
187
	if ((set = ber_add_set(NULL)) == NULL)
188
		goto fail;
189
	if (ber_add_string(set, uuid_str) == NULL)
190
		goto fail;
191
	if (ldap_add_attribute(attrs, "entryUUID", set) == NULL)
192
		goto fail;
193
194
	if ((rc = validate_entry(dn, attrs, ns->relax)) != LDAP_SUCCESS ||
195
	    namespace_add(ns, dn, attrs) != 0) {
196
		namespace_abort(ns);
197
		if (rc == LDAP_SUCCESS && errno == EEXIST)
198
			rc = LDAP_ALREADY_EXISTS;
199
		else if (rc == LDAP_SUCCESS)
200
			rc = LDAP_OTHER;
201
	} else if (namespace_commit(ns) != 0)
202
		rc = LDAP_OTHER;
203
204
	return ldap_respond(req, rc);
205
206
fail:
207
	if (set != NULL)
208
		ber_free_elements(set);
209
	namespace_abort(ns);
210
	return ldap_respond(req, LDAP_OTHER);
211
}
212
213
int
214
ldap_modify(struct request *req)
215
{
216
	int			 rc = LDAP_OTHER;
217
	char			*dn;
218
	long long		 op;
219
	char			*attr;
220
	struct ber_element	*mods, *entry, *mod, *a, *set;
221
	struct ber_element	*vals = NULL, *prev = NULL;
222
	struct namespace	*ns;
223
	struct attr_type	*at;
224
	struct referrals	*refs;
225
226
	++stats.req_mod;
227
228
	if (ber_scanf_elements(req->op, "{se", &dn, &mods) != 0)
229
		return ldap_respond(req, LDAP_PROTOCOL_ERROR);
230
231
	normalize_dn(dn);
232
	log_debug("modifying dn %s", dn);
233
234
	if (*dn == 0)
235
		return ldap_respond(req, LDAP_INVALID_DN_SYNTAX);
236
237
	if ((ns = namespace_for_base(dn)) == NULL) {
238
		refs = namespace_referrals(dn);
239
		if (refs == NULL)
240
			return ldap_respond(req, LDAP_NAMING_VIOLATION);
241
		else
242
			return ldap_refer(req, dn, NULL, refs);
243
	}
244
245
	if (!authorized(req->conn, ns, ACI_WRITE, dn, LDAP_SCOPE_BASE))
246
		return ldap_respond(req, LDAP_INSUFFICIENT_ACCESS);
247
248
	if (namespace_begin(ns) == -1) {
249
		if (errno == EBUSY) {
250
			if (namespace_queue_request(ns, req) != 0)
251
				return ldap_respond(req, LDAP_BUSY);
252
			return LDAP_BUSY;
253
		}
254
		return ldap_respond(req, LDAP_OTHER);
255
	}
256
257
	if ((entry = namespace_get(ns, dn)) == NULL) {
258
		rc = LDAP_NO_SUCH_OBJECT;
259
		goto done;
260
	}
261
262
	for (mod = mods->be_sub; mod; mod = mod->be_next) {
263
		if (ber_scanf_elements(mod, "{E{ese(", &op, &prev, &attr, &vals) != 0) {
264
			rc = LDAP_PROTOCOL_ERROR;
265
			vals = NULL;
266
			goto done;
267
		}
268
269
		prev->be_next = NULL;
270
271
		if (!ns->relax) {
272
			at = lookup_attribute(conf->schema, attr);
273
			if (at == NULL) {
274
				log_debug("unknown attribute type %s", attr);
275
				rc = LDAP_NO_SUCH_ATTRIBUTE;
276
				goto done;
277
			}
278
			if (at->immutable) {
279
				log_debug("attempt to modify immutable"
280
				    " attribute %s", attr);
281
				rc = LDAP_CONSTRAINT_VIOLATION;
282
				goto done;
283
			}
284
		}
285
286
		a = ldap_get_attribute(entry, attr);
287
288
		switch (op) {
289
		case LDAP_MOD_ADD:
290
			if (a == NULL) {
291
				if (ldap_add_attribute(entry, attr, vals) != NULL)
292
					vals = NULL;
293
			} else {
294
				if (ldap_merge_values(a, vals) == 0)
295
					vals = NULL;
296
			}
297
			break;
298
		case LDAP_MOD_DELETE:
299
			/*
300
			 * We're already in the "SET OF value
301
			 * AttributeValue" (see RFC2411 section
302
			 * 4.1.7) have either EOC, so all values
303
			 * for the attribute gets deleted, or we
304
			 * have a (first) octetstring (there is one
305
			 * for each AttributeValue to be deleted)
306
			 */
307
			if (vals->be_sub &&
308
			    vals->be_sub->be_type == BER_TYPE_OCTETSTRING) {
309
				ldap_del_values(a, vals);
310
			} else {
311
				ldap_del_attribute(entry, attr);
312
			}
313
			break;
314
		case LDAP_MOD_REPLACE:
315
			if (vals->be_sub != NULL &&
316
			    vals->be_sub->be_type != BER_TYPE_EOC) {
317
				if (a == NULL) {
318
					if (ldap_add_attribute(entry, attr, vals) != NULL)
319
						vals = NULL;
320
				} else {
321
					if (ldap_set_values(a, vals) == 0)
322
						vals = NULL;
323
				}
324
			} else if (a != NULL)
325
				ldap_del_attribute(entry, attr);
326
			break;
327
		}
328
329
		if (vals != NULL) {
330
			ber_free_elements(vals);
331
			vals = NULL;
332
		}
333
	}
334
335
	if ((rc = validate_entry(dn, entry, ns->relax)) != LDAP_SUCCESS)
336
		goto done;
337
338
	set = ber_add_set(NULL);
339
	ber_add_string(set, req->conn->binddn ? req->conn->binddn : "");
340
	if ((a = ldap_get_attribute(entry, "modifiersName")) != NULL)
341
		ldap_set_values(a, set);
342
	else
343
		ldap_add_attribute(entry, "modifiersName", set);
344
345
	set = ber_add_set(NULL);
346
	ber_add_string(set, ldap_now());
347
	if ((a = ldap_get_attribute(entry, "modifyTimestamp")) != NULL)
348
		ldap_set_values(a, set);
349
	else
350
		ldap_add_attribute(entry, "modifyTimestamp", set);
351
352
	if (namespace_update(ns, dn, entry) == 0 && namespace_commit(ns) == 0)
353
		rc = LDAP_SUCCESS;
354
	else
355
		rc = LDAP_OTHER;
356
357
done:
358
	if (vals != NULL)
359
		ber_free_elements(vals);
360
	namespace_abort(ns);
361
	return ldap_respond(req, rc);
362
}
363