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