1 /* $OpenBSD: util.c,v 1.23 2001/10/26 13:29:26 ho Exp $ */ 2 /* $EOM: util.c,v 1.23 2000/11/23 12:22:08 niklas Exp $ */ 3 4 /* 5 * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. 6 * Copyright (c) 2000, 2001 H�kan Olsson. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Ericsson Radio Systems. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * This code was written under funding by Ericsson Radio Systems. 36 */ 37 38 #include <sys/types.h> 39 #include <sys/socket.h> 40 #include <sys/stat.h> 41 #include <netinet/in.h> 42 #include <arpa/inet.h> 43 #include <limits.h> 44 #include <netdb.h> 45 #include <stdlib.h> 46 #include <string.h> 47 #include <unistd.h> 48 #include <errno.h> 49 50 #include "sysdep.h" 51 52 #include "log.h" 53 #include "message.h" 54 #include "sysdep.h" 55 #include "transport.h" 56 #include "util.h" 57 58 /* 59 * Set if -N is given, allowing name lookups to be done, possibly stalling 60 * the daemon for quite a while. 61 */ 62 int allow_name_lookups = 0; 63 64 /* 65 * This is set to true in case of regression-test mode, when it will 66 * cause predictable random numbers be generated. 67 */ 68 int regrand = 0; 69 70 /* 71 * If in regression-test mode, this is the seed used. 72 */ 73 unsigned long seed; 74 75 /* 76 * XXX These might be turned into inlines or macros, maybe even 77 * machine-dependent ones, for performance reasons. 78 */ 79 u_int16_t 80 decode_16 (u_int8_t *cp) 81 { 82 return cp[0] << 8 | cp[1]; 83 } 84 85 u_int32_t 86 decode_32 (u_int8_t *cp) 87 { 88 return cp[0] << 24 | cp[1] << 16 | cp[2] << 8 | cp[3]; 89 } 90 91 u_int64_t 92 decode_64 (u_int8_t *cp) 93 { 94 return (u_int64_t)cp[0] << 56 | (u_int64_t)cp[1] << 48 95 | (u_int64_t)cp[2] << 40 | (u_int64_t)cp[3] << 32 96 | cp[4] << 24 | cp[5] << 16 | cp[6] << 8 | cp[7]; 97 } 98 99 #if 0 100 /* 101 * XXX I severly doubt that we will need this. IPv6 does not have the legacy 102 * of representation in host byte order, AFAIK. 103 */ 104 105 void 106 decode_128 (u_int8_t *cp, u_int8_t *cpp) 107 { 108 #if BYTE_ORDER == LITTLE_ENDIAN 109 int i; 110 111 for (i = 0; i < 16; i++) 112 cpp[i] = cp[15 - i]; 113 #elif BYTE_ORDER == BIG_ENDIAN 114 bcopy (cp, cpp, 16); 115 #else 116 #error "Byte order unknown!" 117 #endif 118 } 119 #endif 120 121 void 122 encode_16 (u_int8_t *cp, u_int16_t x) 123 { 124 *cp++ = x >> 8; 125 *cp = x & 0xff; 126 } 127 128 void 129 encode_32 (u_int8_t *cp, u_int32_t x) 130 { 131 *cp++ = x >> 24; 132 *cp++ = (x >> 16) & 0xff; 133 *cp++ = (x >> 8) & 0xff; 134 *cp = x & 0xff; 135 } 136 137 void 138 encode_64 (u_int8_t *cp, u_int64_t x) 139 { 140 *cp++ = x >> 56; 141 *cp++ = (x >> 48) & 0xff; 142 *cp++ = (x >> 40) & 0xff; 143 *cp++ = (x >> 32) & 0xff; 144 *cp++ = (x >> 24) & 0xff; 145 *cp++ = (x >> 16) & 0xff; 146 *cp++ = (x >> 8) & 0xff; 147 *cp = x & 0xff; 148 } 149 150 #if 0 151 /* 152 * XXX I severly doubt that we will need this. IPv6 does not have the legacy 153 * of representation in host byte order, AFAIK. 154 */ 155 156 void 157 encode_128 (u_int8_t *cp, u_int8_t *cpp) 158 { 159 decode_128 (cpp, cp); 160 } 161 #endif 162 163 /* Check a buffer for all zeroes. */ 164 int 165 zero_test (const u_int8_t *p, size_t sz) 166 { 167 while (sz-- > 0) 168 if (*p++ != 0) 169 return 0; 170 return 1; 171 } 172 173 /* Check a buffer for all ones. */ 174 int 175 ones_test (const u_int8_t *p, size_t sz) 176 { 177 while (sz-- > 0) 178 if (*p++ != 0xff) 179 return 0; 180 return 1; 181 } 182 183 /* 184 * Generate a random data, len bytes long. 185 */ 186 u_int8_t * 187 getrandom (u_int8_t *buf, size_t len) 188 { 189 u_int32_t tmp = 0; 190 int i; 191 192 for (i = 0; i < len; i++) 193 { 194 if (i % sizeof tmp == 0) 195 tmp = sysdep_random (); 196 197 buf[i] = tmp & 0xff; 198 tmp >>= 8; 199 } 200 201 return buf; 202 } 203 204 static __inline int 205 hex2nibble (char c) 206 { 207 if (c >= '0' && c <= '9') 208 return c - '0'; 209 if (c >= 'a' && c <= 'f') 210 return c - 'a' + 10; 211 if (c >= 'A' && c <= 'F') 212 return c - 'A' + 10; 213 return -1; 214 } 215 216 /* 217 * Convert hexadecimal string in S to raw binary buffer at BUF sized SZ 218 * bytes. Return 0 if everything is OK, -1 otherwise. 219 */ 220 int 221 hex2raw (char *s, u_int8_t *buf, size_t sz) 222 { 223 char *p; 224 u_int8_t *bp; 225 int tmp; 226 227 if (strlen (s) > sz * 2) 228 return -1; 229 for (p = s + strlen (s) - 1, bp = &buf[sz - 1]; bp >= buf; bp--) 230 { 231 *bp = 0; 232 if (p >= s) 233 { 234 tmp = hex2nibble (*p--); 235 if (tmp == -1) 236 return -1; 237 *bp = tmp; 238 } 239 if (p >= s) 240 { 241 tmp = hex2nibble (*p--); 242 if (tmp == -1) 243 return -1; 244 *bp |= tmp << 4; 245 } 246 } 247 return 0; 248 } 249 250 int 251 text2sockaddr (char *address, char *port, struct sockaddr **sa) 252 { 253 #ifdef HAVE_GETNAMEINFO 254 struct addrinfo *ai, hints; 255 256 memset (&hints, 0, sizeof hints); 257 if (!allow_name_lookups) 258 hints.ai_flags = AI_NUMERICHOST; 259 hints.ai_family = PF_UNSPEC; 260 hints.ai_socktype = SOCK_DGRAM; 261 hints.ai_protocol = IPPROTO_UDP; 262 263 if (getaddrinfo (address, port, &hints, &ai)) 264 return -1; 265 266 *sa = malloc (sysdep_sa_len (ai->ai_addr)); 267 if (!sa) 268 return -1; 269 270 memcpy (*sa, ai->ai_addr, sysdep_sa_len (ai->ai_addr)); 271 freeaddrinfo (ai); 272 return 0; 273 #else 274 int af = strchr (address, ':') != NULL ? AF_INET6 : AF_INET; 275 size_t sz = af == AF_INET 276 ? sizeof (struct sockaddr_in) : sizeof (struct sockaddr_in6); 277 long lport; 278 struct servent *sp; 279 char *ep; 280 281 *sa = calloc (1, sz); 282 if (!*sa) 283 return -1; 284 285 #ifndef USE_OLD_SOCKADDR 286 (*sa)->sa_len = sz; 287 #endif 288 (*sa)->sa_family = af; 289 if (inet_pton (af, address, sockaddr_addrdata (*sa)) != 1) 290 { 291 free (*sa); 292 return -1; 293 } 294 sp = getservbyname (port, "udp"); 295 if (!sp) 296 { 297 lport = strtol (port, &ep, 10); 298 if (ep == port || lport < 0 || lport > USHRT_MAX) 299 { 300 free (*sa); 301 return -1; 302 } 303 lport = htons (lport); 304 } 305 else 306 lport = sp->s_port; 307 if ((*sa)->sa_family == AF_INET) 308 ((struct sockaddr_in *)*sa)->sin_port = lport; 309 else 310 ((struct sockaddr_in6 *)*sa)->sin6_port = lport; 311 return 0; 312 #endif 313 } 314 315 /* 316 * Convert a sockaddr to text. With zflag non-zero fill out with zeroes, 317 * i.e 10.0.0.10 --> "010.000.000.010" 318 */ 319 int 320 sockaddr2text (struct sockaddr *sa, char **address, int zflag) 321 { 322 char buf[NI_MAXHOST]; 323 char *token, *bstart, *ep; 324 int addrlen; 325 long val; 326 int i, j; 327 328 #ifdef HAVE_GETNAMEINFO 329 if (getnameinfo (sa, sysdep_sa_len (sa), buf, sizeof buf, 0, 0, 330 allow_name_lookups ? 0 : NI_NUMERICHOST)) 331 return -1; 332 #else 333 switch (sa->sa_family) 334 { 335 case AF_INET: 336 case AF_INET6: 337 if (inet_ntop (sa->sa_family, sa->sa_data, buf, NI_MAXHOST - 1) == NULL) 338 { 339 log_error ("sockaddr2text: inet_ntop (%d, %p, %p, %d) failed", 340 sa->sa_family, sa->sa_data, buf, NI_MAXHOST - 1); 341 return -1; 342 } 343 buf[NI_MAXHOST - 1] = '\0'; 344 break; 345 346 default: 347 log_print ("sockaddr2text: unsupported protocol family %d\n", 348 sa->sa_family); 349 return -1; 350 } 351 #endif 352 353 if (zflag == 0) 354 { 355 *address = malloc (strlen (buf) + 1); 356 if (!*address) 357 return -1; 358 strcpy (*address, buf); 359 } 360 else 361 switch (sa->sa_family) 362 { 363 case AF_INET: 364 addrlen = sizeof "000.000.000.000"; 365 *address = malloc (addrlen); 366 if (!*address) 367 return -1; 368 buf[addrlen] = '\0'; 369 bstart = buf; 370 **address = '\0'; 371 while ((token = strsep (&bstart, ".")) != NULL) 372 { 373 if (strlen (*address) > 12) 374 { 375 free (*address); 376 return -1; 377 } 378 val = strtol (token, &ep, 10); 379 if (ep == token || val < 0 || val > UCHAR_MAX) 380 { 381 free (*address); 382 return -1; 383 } 384 sprintf (*address + strlen (*address), "%03ld", val); 385 if (bstart) 386 strcat (*address + strlen (*address), "."); 387 } 388 break; 389 390 case AF_INET6: 391 /* 392 * XXX In the algorithm below there are some magic numbers we 393 * probably could give explaining names. 394 */ 395 addrlen = sizeof "0000:0000:0000:0000:0000:0000:0000:0000"; 396 *address = malloc (addrlen); 397 if (!*address) 398 return -1; 399 400 for (i = 0, j = 0; i < 8; i++) 401 j += sprintf ((*address) + j, "%02x%02x:", 402 ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2 * i], 403 ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr[2 * i + 1]); 404 (*address)[j - 1] = '\0'; 405 break; 406 407 default: 408 strcpy (*address, "<error>"); 409 } 410 411 return 0; 412 } 413 414 /* 415 * sockaddr_addrlen and sockaddr_addrdata return the relevant sockaddr info 416 * depending on address family. Useful to keep other code shorter(/clearer?). 417 */ 418 int 419 sockaddr_addrlen (struct sockaddr *sa) 420 { 421 switch (sa->sa_family) 422 { 423 case AF_INET6: 424 return sizeof ((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; 425 case AF_INET: 426 return sizeof ((struct sockaddr_in *)sa)->sin_addr.s_addr; 427 default: 428 log_print ("sockaddr_addrlen: unsupported protocol family %d", 429 sa->sa_family); 430 return 0; 431 } 432 } 433 434 u_int8_t * 435 sockaddr_addrdata (struct sockaddr *sa) 436 { 437 switch (sa->sa_family) 438 { 439 case AF_INET6: 440 return (u_int8_t *)&((struct sockaddr_in6 *)sa)->sin6_addr.s6_addr; 441 case AF_INET: 442 return (u_int8_t *)&((struct sockaddr_in *)sa)->sin_addr.s_addr; 443 default: 444 log_print ("sockaddr_addrdata: unsupported protocol family %d", 445 sa->sa_family); 446 return 0; 447 } 448 } 449 450 /* 451 * Convert network address to text. The network address does not need 452 * to be properly aligned. 453 */ 454 void 455 util_ntoa (char **buf, int af, u_int8_t *addr) 456 { 457 struct sockaddr_storage from; 458 struct sockaddr *sfrom = (struct sockaddr *)&from; 459 socklen_t fromlen = sizeof from; 460 461 memset (&from, 0, fromlen); 462 sfrom->sa_family = af; 463 #ifndef USE_OLD_SOCKADDR 464 sfrom->sa_len = sysdep_sa_len (sfrom); 465 #endif 466 memcpy (sockaddr_addrdata (sfrom), addr, sockaddr_addrlen (sfrom)); 467 468 if (sockaddr2text (sfrom, buf, 0)) 469 { 470 log_print ("util_ntoa: " 471 "could not make printable address out of sockaddr %p", sfrom); 472 *buf = 0; 473 } 474 } 475 476 /* 477 * Perform sanity check on files containing secret information. 478 * Returns -1 on failure, 0 otherwise. 479 * Also, if FILE_SIZE is a not a null pointer, store file size here. 480 */ 481 int 482 check_file_secrecy (char *name, off_t *file_size) 483 { 484 struct stat st; 485 486 if (stat (name, &st) == -1) 487 { 488 log_error ("check_file_secrecy: stat (\"%s\") failed", name); 489 return -1; 490 } 491 if (st.st_uid != geteuid () && st.st_uid != getuid ()) 492 { 493 log_print ("check_file_secrecy: " 494 "not loading %s - file owner is not process user", name); 495 errno = EPERM; 496 return -1; 497 } 498 if ((st.st_mode & (S_IRWXG | S_IRWXO)) != 0) 499 { 500 log_print ("conf_file_secrecy: not loading %s - too open permissions", 501 name); 502 errno = EPERM; 503 return -1; 504 } 505 506 if (file_size) 507 *file_size = st.st_size; 508 509 return 0; 510 } 511