xref: /openbsd/usr.sbin/ldapd/util.c (revision 225a5b88)
1 /*	$OpenBSD: util.c,v 1.14 2021/12/15 20:43:31 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 <errno.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include <unistd.h>
33 #include <zlib.h>
34 
35 #include "ldapd.h"
36 #include "log.h"
37 
38 int
bsnprintf(char * str,size_t size,const char * format,...)39 bsnprintf(char *str, size_t size, const char *format, ...)
40 {
41 	int ret;
42 	va_list ap;
43 
44 	va_start(ap, format);
45 	ret = vsnprintf(str, size, format, ap);
46 	va_end(ap);
47 	if (ret < 0 || (size_t)ret >= size)
48 		return 0;
49 
50 	return 1;
51 }
52 
53 /* Normalize a DN in preparation for searches.
54  * Modifies its argument.
55  * Currently only made lowercase, and spaces around comma is removed.
56  * TODO: unescape backslash escapes, handle UTF-8.
57  */
58 void
normalize_dn(char * dn)59 normalize_dn(char *dn)
60 {
61 	size_t		 n;
62 	char		*s, *p;
63 
64 	for (s = p = dn; *s != '\0'; s++) {
65 		if (*s == ' ') {
66 			if (p == dn || p[-1] == ',')
67 				continue;
68 			n = strspn(s, " ");
69 			if (s[n] == '\0' || s[n] == ',')
70 				continue;
71 		}
72 		*p++ = tolower((unsigned char)*s);
73 	}
74 	*p = '\0';
75 }
76 
77 /* Returns true (1) if key ends with suffix.
78  */
79 int
has_suffix(struct btval * key,const char * suffix)80 has_suffix(struct btval *key, const char *suffix)
81 {
82 	size_t		slen;
83 
84 	slen = strlen(suffix);
85 
86 	if (key->size < slen)
87 		return 0;
88 	return (bcmp((char *)key->data + key->size - slen, suffix, slen) == 0);
89 }
90 
91 /* Returns true (1) if key begins with prefix.
92  */
93 int
has_prefix(struct btval * key,const char * prefix)94 has_prefix(struct btval *key, const char *prefix)
95 {
96 	size_t		 pfxlen;
97 
98 	pfxlen = strlen(prefix);
99 	if (pfxlen > key->size)
100 		return 0;
101 	return (memcmp(key->data, prefix, pfxlen) == 0);
102 }
103 
104 int
ber2db(struct ber_element * root,struct btval * val,int compression_level)105 ber2db(struct ber_element *root, struct btval *val, int compression_level)
106 {
107 	int			 rc;
108 	ssize_t			 len;
109 	uLongf			 destlen;
110 	Bytef			*dest;
111 	void			*buf;
112 	struct ber		 ber;
113 
114 	memset(val, 0, sizeof(*val));
115 
116 	memset(&ber, 0, sizeof(ber));
117 	ober_write_elements(&ber, root);
118 
119 	if ((len = ober_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(%zu)", val->size + sizeof(uint32_t));
127 			ober_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 			ober_free(&ber);
137 			return -1;
138 		}
139 		log_debug("compressed entry from %zd -> %lu 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 	ober_free(&ber);
153 
154 	return 0;
155 }
156 
157 struct ber_element *
db2ber(struct btval * val,int compression_level)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 
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(%lu)", 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 %zu -> %lu byte",
192 		    val->size, len);
193 
194 		ober_set_readbuf(&ber, buf, len);
195 		elm = ober_read_elements(&ber, NULL);
196 		free(buf);
197 		return elm;
198 	} else {
199 		ober_set_readbuf(&ber, val->data, val->size);
200 		return ober_read_elements(&ber, NULL);
201 	}
202 }
203 
204 int
accept_reserve(int sockfd,struct sockaddr * addr,socklen_t * addrlen,int reserve)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