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