xref: /openbsd-src/usr.sbin/ldapd/util.c (revision 4e1ee0786f11cc571bd0be17d38e46f635c719fc)
1 /*	$OpenBSD: util.c,v 1.13 2020/11/29 20:04:36 tb 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 #include <sys/socket.h>
22 #include <sys/resource.h>
23 #include <netinet/in.h>
24 #include <arpa/inet.h>
25 
26 #include <assert.h>
27 #include <ctype.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <zlib.h>
32 #include <errno.h>
33 
34 #include "ldapd.h"
35 #include "log.h"
36 
37 int
38 bsnprintf(char *str, size_t size, const char *format, ...)
39 {
40 	int ret;
41 	va_list ap;
42 
43 	va_start(ap, format);
44 	ret = vsnprintf(str, size, format, ap);
45 	va_end(ap);
46 	if (ret < 0 || (size_t)ret >= size)
47 		return 0;
48 
49 	return 1;
50 }
51 
52 /* Normalize a DN in preparation for searches.
53  * Modifies its argument.
54  * Currently only made lowercase, and spaces around comma is removed.
55  * TODO: unescape backslash escapes, handle UTF-8.
56  */
57 void
58 normalize_dn(char *dn)
59 {
60 	size_t		 n;
61 	char		*s, *p;
62 
63 	for (s = p = dn; *s != '\0'; s++) {
64 		if (*s == ' ') {
65 			if (p == dn || p[-1] == ',')
66 				continue;
67 			n = strspn(s, " ");
68 			if (s[n] == '\0' || s[n] == ',')
69 				continue;
70 		}
71 		*p++ = tolower((unsigned char)*s);
72 	}
73 	*p = '\0';
74 }
75 
76 /* Returns true (1) if key ends with suffix.
77  */
78 int
79 has_suffix(struct btval *key, const char *suffix)
80 {
81 	size_t		slen;
82 
83 	slen = strlen(suffix);
84 
85 	if (key->size < slen)
86 		return 0;
87 	return (bcmp((char *)key->data + key->size - slen, suffix, slen) == 0);
88 }
89 
90 /* Returns true (1) if key begins with prefix.
91  */
92 int
93 has_prefix(struct btval *key, const char *prefix)
94 {
95 	size_t		 pfxlen;
96 
97 	pfxlen = strlen(prefix);
98 	if (pfxlen > key->size)
99 		return 0;
100 	return (memcmp(key->data, prefix, pfxlen) == 0);
101 }
102 
103 int
104 ber2db(struct ber_element *root, struct btval *val, int compression_level)
105 {
106 	int			 rc;
107 	ssize_t			 len;
108 	uLongf			 destlen;
109 	Bytef			*dest;
110 	void			*buf;
111 	struct ber		 ber;
112 
113 	memset(val, 0, sizeof(*val));
114 
115 	memset(&ber, 0, sizeof(ber));
116 	ober_write_elements(&ber, root);
117 
118 	if ((len = ober_get_writebuf(&ber, &buf)) == -1)
119 		return -1;
120 
121 	if (compression_level > 0) {
122 		val->size = compressBound(len);
123 		val->data = malloc(val->size + sizeof(uint32_t));
124 		if (val->data == NULL) {
125 			log_warn("malloc(%zu)", val->size + sizeof(uint32_t));
126 			ober_free(&ber);
127 			return -1;
128 		}
129 		dest = (char *)val->data + sizeof(uint32_t);
130 		destlen = val->size - sizeof(uint32_t);
131 		if ((rc = compress2(dest, &destlen, buf, len,
132 		    compression_level)) != Z_OK) {
133 			log_warn("compress returned %d", rc);
134 			free(val->data);
135 			ober_free(&ber);
136 			return -1;
137 		}
138 		log_debug("compressed entry from %zd -> %lu byte",
139 		    len, destlen + sizeof(uint32_t));
140 
141 		*(uint32_t *)val->data = len;
142 		val->size = destlen + sizeof(uint32_t);
143 		val->free_data = 1;
144 	} else {
145 		val->data = buf;
146 		val->size = len;
147 		val->free_data = 1;	/* XXX: take over internal br_wbuf */
148 		ber.br_wbuf = NULL;
149 	}
150 
151 	ober_free(&ber);
152 
153 	return 0;
154 }
155 
156 struct ber_element *
157 db2ber(struct btval *val, int compression_level)
158 {
159 	int			 rc;
160 	uLongf			 len;
161 	void			*buf;
162 	Bytef			*src;
163 	uLong			 srclen;
164 	struct ber_element	*elm;
165 	struct ber		 ber;
166 
167 	assert(val != NULL);
168 
169 	memset(&ber, 0, sizeof(ber));
170 
171 	if (compression_level > 0) {
172 		if (val->size < sizeof(uint32_t))
173 			return NULL;
174 
175 		len = *(uint32_t *)val->data;
176 		if ((buf = malloc(len)) == NULL) {
177 			log_warn("malloc(%lu)", len);
178 			return NULL;
179 		}
180 
181 		src = (char *)val->data + sizeof(uint32_t);
182 		srclen = val->size - sizeof(uint32_t);
183 		rc = uncompress(buf, &len, src, srclen);
184 		if (rc != Z_OK) {
185 			log_warnx("dbt_to_ber: uncompress returned %d", rc);
186 			free(buf);
187 			return NULL;
188 		}
189 
190 		log_debug("uncompressed entry from %zu -> %lu byte",
191 		    val->size, len);
192 
193 		ober_set_readbuf(&ber, buf, len);
194 		elm = ober_read_elements(&ber, NULL);
195 		free(buf);
196 		return elm;
197 	} else {
198 		ober_set_readbuf(&ber, val->data, val->size);
199 		return ober_read_elements(&ber, NULL);
200 	}
201 }
202 
203 int
204 accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
205     int reserve)
206 {
207 	if (getdtablecount() + reserve >= getdtablesize()) {
208 		errno = EMFILE;
209 		return -1;
210 	}
211 
212 	return accept4(sockfd, addr, addrlen, SOCK_NONBLOCK);
213 }
214