xref: /openbsd-src/usr.sbin/ldapd/util.c (revision ae3cb403620ab940fbaabb3055fac045a63d56b7)
1 /*	$OpenBSD: util.c,v 1.8 2017/01/20 11:55:08 benno 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 == -1 || ret >= (int)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 	ber.fd = -1;
117 	ber_write_elements(&ber, root);
118 
119 	if ((len = ber_get_writebuf(&ber, &buf)) == -1)
120 		return -1;
121 
122 	if (compression_level > 0) {
123 		val->size = compressBound(len);
124 		val->data = malloc(val->size + sizeof(uint32_t));
125 		if (val->data == NULL) {
126 			log_warn("malloc(%u)", val->size + sizeof(uint32_t));
127 			ber_free(&ber);
128 			return -1;
129 		}
130 		dest = (char *)val->data + sizeof(uint32_t);
131 		destlen = val->size - sizeof(uint32_t);
132 		if ((rc = compress2(dest, &destlen, buf, len,
133 		    compression_level)) != Z_OK) {
134 			log_warn("compress returned %d", rc);
135 			free(val->data);
136 			ber_free(&ber);
137 			return -1;
138 		}
139 		log_debug("compressed entry from %u -> %u byte",
140 		    len, destlen + sizeof(uint32_t));
141 
142 		*(uint32_t *)val->data = len;
143 		val->size = destlen + sizeof(uint32_t);
144 		val->free_data = 1;
145 	} else {
146 		val->data = buf;
147 		val->size = len;
148 		val->free_data = 1;	/* XXX: take over internal br_wbuf */
149 		ber.br_wbuf = NULL;
150 	}
151 
152 	ber_free(&ber);
153 
154 	return 0;
155 }
156 
157 struct ber_element *
158 db2ber(struct btval *val, int compression_level)
159 {
160 	int			 rc;
161 	uLongf			 len;
162 	void			*buf;
163 	Bytef			*src;
164 	uLong			 srclen;
165 	struct ber_element	*elm;
166 	struct ber		 ber;
167 
168 	assert(val != NULL);
169 
170 	memset(&ber, 0, sizeof(ber));
171 	ber.fd = -1;
172 
173 	if (compression_level > 0) {
174 		if (val->size < sizeof(uint32_t))
175 			return NULL;
176 
177 		len = *(uint32_t *)val->data;
178 		if ((buf = malloc(len)) == NULL) {
179 			log_warn("malloc(%u)", len);
180 			return NULL;
181 		}
182 
183 		src = (char *)val->data + sizeof(uint32_t);
184 		srclen = val->size - sizeof(uint32_t);
185 		rc = uncompress(buf, &len, src, srclen);
186 		if (rc != Z_OK) {
187 			log_warnx("dbt_to_ber: uncompress returned %d", rc);
188 			free(buf);
189 			return NULL;
190 		}
191 
192 		log_debug("uncompressed entry from %u -> %u byte",
193 		    val->size, len);
194 
195 		ber_set_readbuf(&ber, buf, len);
196 		elm = ber_read_elements(&ber, NULL);
197 		free(buf);
198 		return elm;
199 	} else {
200 		ber_set_readbuf(&ber, val->data, val->size);
201 		return ber_read_elements(&ber, NULL);
202 	}
203 }
204 
205 int
206 accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
207     int reserve)
208 {
209 	if (getdtablecount() + reserve >= getdtablesize()) {
210 		errno = EMFILE;
211 		return -1;
212 	}
213 
214 	return accept4(sockfd, addr, addrlen, SOCK_NONBLOCK);
215 }
216