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