1/*	$OpenBSD: attributes.c,v 1.7 2021/12/20 13:26:11 claudio Exp $ */
2
3/*
4 * Copyright (c) 2009 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/queue.h>
20#include <sys/types.h>
21
22#include <assert.h>
23#include <string.h>
24#include <time.h>
25
26#include "ldapd.h"
27#include "log.h"
28
29struct ber_element *
30ldap_get_attribute(struct ber_element *entry, const char *attr)
31{
32	char			*s;
33	struct ber_element	*elm, *a;
34
35	assert(entry);
36	assert(attr);
37	if (entry->be_encoding != BER_TYPE_SEQUENCE)
38		return NULL;
39
40	for (elm = entry->be_sub; elm != NULL; elm = elm->be_next) {
41		a = elm->be_sub;
42		if (a && ober_get_string(a, &s) == 0 && strcasecmp(s, attr) == 0)
43			return a;
44	}
45
46	return NULL;
47}
48
49struct ber_element *
50ldap_find_attribute(struct ber_element *entry, struct attr_type *at)
51{
52	struct ber_element	*elm = NULL;
53	struct name		*an;
54
55	SLIST_FOREACH(an, at->names, next) {
56		if ((elm = ldap_get_attribute(entry, an->name)) != NULL)
57			return elm;
58	}
59	if (an == NULL)
60		elm = ldap_get_attribute(entry, at->oid);
61
62	return elm;
63}
64
65struct ber_element *
66ldap_find_value(struct ber_element *elm, const char *value)
67{
68	char			*s;
69	struct ber_element	*a;
70
71	if (elm == NULL)
72		return NULL;
73
74	for (a = elm->be_sub; a != NULL; a = a->be_next) {
75		if (ober_get_string(a, &s) == 0 && strcasecmp(s, value) == 0)
76			return a;
77	}
78
79	return NULL;
80}
81
82struct ber_element *
83ldap_add_attribute(struct ber_element *entry, const char *attr,
84	struct ber_element *value_set)
85{
86	struct ber_element	*elm, *a, *last;
87
88	assert(entry);
89	assert(attr);
90	assert(value_set);
91
92	if (entry->be_encoding != BER_TYPE_SEQUENCE) {
93		log_warnx("entries should be a sequence");
94		return NULL;
95	}
96
97	if (value_set->be_type != BER_TYPE_SET) {
98		log_warnx("values should be a set");
99		return NULL;
100	}
101
102	last = entry->be_sub;
103	if (last == NULL)
104		last = entry;
105	else while (last != NULL && last->be_next != NULL)
106		last = last->be_next;
107
108	if ((elm = ober_add_sequence(last)) == NULL)
109		return NULL;
110	if ((a = ober_add_string(elm, attr)) == NULL) {
111		ober_free_elements(elm);
112		return NULL;
113	}
114	ober_link_elements(a, value_set);
115
116	return elm;
117}
118
119int
120ldap_set_values(struct ber_element *elm, struct ber_element *vals)
121{
122	char			*attr;
123	struct ber_element	*old_vals;
124
125	assert(elm);
126	assert(vals);
127	assert(vals->be_sub);
128
129	if (ober_scanf_elements(elm, "se(", &attr, &old_vals) != 0) {
130		log_warnx("failed to parse element");
131		return -1;
132	}
133
134	ober_free_elements(old_vals->be_sub);
135	old_vals->be_sub = NULL;
136	ober_link_elements(old_vals, vals->be_sub);
137
138	vals->be_sub = NULL;
139	ober_free_elements(vals);
140
141	return 0;
142}
143
144int
145ldap_merge_values(struct ber_element *elm, struct ber_element *vals)
146{
147	char			*attr;
148	struct ber_element	*old_vals, *last;
149
150	assert(elm);
151	assert(vals);
152	assert(vals->be_type == BER_TYPE_SET);
153	assert(vals->be_sub);
154
155	if (ober_scanf_elements(elm, "se(", &attr, &old_vals) != 0) {
156		log_warnx("failed to parse element");
157		return -1;
158	}
159
160	last = old_vals->be_sub;
161	while (last && last->be_next)
162		last = last->be_next;
163
164	ober_link_elements(last, vals->be_sub);
165
166	vals->be_sub = NULL;
167	ober_free_elements(vals);
168
169	return 0;
170}
171
172
173int
174ldap_del_attribute(struct ber_element *entry, const char *attrdesc)
175{
176	struct ber_element	*attr, *prev = NULL;
177	char			*s;
178
179	assert(entry);
180	assert(attrdesc);
181
182	attr = entry->be_sub;
183	while (attr) {
184		if (ober_scanf_elements(attr, "{s", &s) != 0) {
185			log_warnx("failed to parse attribute");
186			return -1;
187		}
188
189		if (strcasecmp(s, attrdesc) == 0) {
190			if (prev == NULL)
191				entry->be_sub = attr->be_next;
192			else
193				prev->be_next = attr->be_next;
194			attr->be_next = NULL;
195			ober_free_elements(attr);
196			break;
197		}
198
199		prev = attr;
200		attr = attr->be_next;
201	}
202
203	return 0;
204}
205
206int
207ldap_del_values(struct ber_element *elm, struct ber_element *vals)
208{
209	char			*attr;
210	struct ber_element	*old_vals, *v, *x, *prev, *next;
211	struct ber_element	*removed;
212	int			removed_p;
213	assert(elm);
214	assert(vals);
215	assert(vals->be_sub);
216
217	if (ober_scanf_elements(elm, "se(", &attr, &old_vals) != 0) {
218		log_warnx("failed to parse element");
219		return -1;
220	}
221
222	prev = old_vals;
223	removed_p = 0;
224	for (v = old_vals->be_sub; v; v = next) {
225		next = v->be_next;
226
227		for (x = vals->be_sub; x; x = x->be_next) {
228			if (x && v->be_len == x->be_len &&
229			    memcmp(v->be_val, x->be_val, x->be_len) == 0) {
230				removed = ober_unlink_elements(prev);
231				ober_link_elements(prev, removed->be_next);
232				ober_free_element(removed);
233				removed_p = 1;
234				break;
235			}
236		}
237		if (removed_p) {
238			removed_p = 0;
239		} else {
240			prev = v;
241		}
242	}
243
244	if (old_vals->be_sub == NULL)
245		return 1;
246
247	return 0;
248}
249
250char *
251ldap_strftime(time_t tm)
252{
253	static char	 tmbuf[16];
254	struct tm	*gmt = gmtime(&tm);
255
256	strftime(tmbuf, sizeof(tmbuf), "%Y%m%d%H%M%SZ", gmt);
257	return tmbuf;
258}
259
260char *
261ldap_now(void)
262{
263	return ldap_strftime(time(0));
264}
265
266