xref: /openbsd-src/usr.sbin/ldapd/util.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /*	$OpenBSD: util.c,v 1.7 2015/12/24 17:47:57 mmcc 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 
36 int
37 bsnprintf(char *str, size_t size, const char *format, ...)
38 {
39 	int ret;
40 	va_list ap;
41 
42 	va_start(ap, format);
43 	ret = vsnprintf(str, size, format, ap);
44 	va_end(ap);
45 	if (ret == -1 || ret >= (int)size)
46 		return 0;
47 
48 	return 1;
49 }
50 
51 /* Normalize a DN in preparation for searches.
52  * Modifies its argument.
53  * Currently only made lowercase, and spaces around comma is removed.
54  * TODO: unescape backslash escapes, handle UTF-8.
55  */
56 void
57 normalize_dn(char *dn)
58 {
59 	size_t		 n;
60 	char		*s, *p;
61 
62 	for (s = p = dn; *s != '\0'; s++) {
63 		if (*s == ' ') {
64 			if (p == dn || p[-1] == ',')
65 				continue;
66 			n = strspn(s, " ");
67 			if (s[n] == '\0' || s[n] == ',')
68 				continue;
69 		}
70 		*p++ = tolower((unsigned char)*s);
71 	}
72 	*p = '\0';
73 }
74 
75 /* Returns true (1) if key ends with suffix.
76  */
77 int
78 has_suffix(struct btval *key, const char *suffix)
79 {
80 	size_t		slen;
81 
82 	slen = strlen(suffix);
83 
84 	if (key->size < slen)
85 		return 0;
86 	return (bcmp((char *)key->data + key->size - slen, suffix, slen) == 0);
87 }
88 
89 /* Returns true (1) if key begins with prefix.
90  */
91 int
92 has_prefix(struct btval *key, const char *prefix)
93 {
94 	size_t		 pfxlen;
95 
96 	pfxlen = strlen(prefix);
97 	if (pfxlen > key->size)
98 		return 0;
99 	return (memcmp(key->data, prefix, pfxlen) == 0);
100 }
101 
102 int
103 ber2db(struct ber_element *root, struct btval *val, int compression_level)
104 {
105 	int			 rc;
106 	ssize_t			 len;
107 	uLongf			 destlen;
108 	Bytef			*dest;
109 	void			*buf;
110 	struct ber		 ber;
111 
112 	memset(val, 0, sizeof(*val));
113 
114 	memset(&ber, 0, sizeof(ber));
115 	ber.fd = -1;
116 	ber_write_elements(&ber, root);
117 
118 	if ((len = ber_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(%u)", val->size + sizeof(uint32_t));
126 			ber_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 			ber_free(&ber);
136 			return -1;
137 		}
138 		log_debug("compressed entry from %u -> %u 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 	ber_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 	ber.fd = -1;
171 
172 	if (compression_level > 0) {
173 		if (val->size < sizeof(uint32_t))
174 			return NULL;
175 
176 		len = *(uint32_t *)val->data;
177 		if ((buf = malloc(len)) == NULL) {
178 			log_warn("malloc(%u)", len);
179 			return NULL;
180 		}
181 
182 		src = (char *)val->data + sizeof(uint32_t);
183 		srclen = val->size - sizeof(uint32_t);
184 		rc = uncompress(buf, &len, src, srclen);
185 		if (rc != Z_OK) {
186 			log_warnx("dbt_to_ber: uncompress returned %d", rc);
187 			free(buf);
188 			return NULL;
189 		}
190 
191 		log_debug("uncompressed entry from %u -> %u byte",
192 		    val->size, len);
193 
194 		ber_set_readbuf(&ber, buf, len);
195 		elm = ber_read_elements(&ber, NULL);
196 		free(buf);
197 		return elm;
198 	} else {
199 		ber_set_readbuf(&ber, val->data, val->size);
200 		return ber_read_elements(&ber, NULL);
201 	}
202 }
203 
204 int
205 accept_reserve(int sockfd, struct sockaddr *addr, socklen_t *addrlen,
206     int reserve)
207 {
208 	if (getdtablecount() + reserve >= getdtablesize()) {
209 		errno = EMFILE;
210 		return -1;
211 	}
212 
213 	return accept4(sockfd, addr, addrlen, SOCK_NONBLOCK);
214 }
215