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 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 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 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 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 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 * 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 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