1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #include <stdio.h> 28 #include <stdlib.h> 29 #include <strings.h> 30 #include <string.h> 31 #include <unistd.h> 32 #include <pthread.h> 33 #include <sys/types.h> 34 #include <sys/socket.h> 35 #include <netinet/in.h> 36 #include <arpa/inet.h> 37 38 #include "ldap_util.h" 39 #include "ldap_glob.h" 40 41 static time_t msgtime[MSG_LASTMSG] = {0}; 42 static time_t msgtimeout = 3600; 43 44 static pthread_key_t tsdKey; 45 46 /* 47 * Log a message to the appropriate place. 48 */ 49 void 50 logmsg(int msgtype, int priority, const char *fmt, ...) { 51 va_list ap; 52 struct timeval tp; 53 54 /* 55 * Only log LOG_INFO priority if 'verbose' is on, or if 56 * msgtype is MSG_ALWAYS. 57 */ 58 if (priority == LOG_INFO && !verbose && msgtype != MSG_ALWAYS) 59 return; 60 61 /* Make sure we don't log the same message too often */ 62 if (msgtype != MSG_NOTIMECHECK && msgtype != MSG_ALWAYS && 63 msgtype > 0 && msgtype < MSG_LASTMSG && 64 gettimeofday(&tp, 0) != -1) { 65 if (tp.tv_sec - msgtime[msgtype] < msgtimeout) 66 return; 67 msgtime[msgtype] = tp.tv_sec; 68 } 69 70 va_start(ap, fmt); 71 if (cons == 0) { 72 vsyslog(priority, fmt, ap); 73 } else { 74 int flen = slen(fmt); 75 76 vfprintf(cons, fmt, ap); 77 /* 78 * If the last character in 'fmt' wasn't a '\n', write one 79 * to the console. 80 */ 81 if (flen > 0 && fmt[flen-1] != '\n') 82 fprintf(cons, "\n"); 83 } 84 va_end(ap); 85 } 86 87 void 88 __destroyTsdKey(void *arg) { 89 __nis_deferred_error_t *defErr = arg; 90 91 if (defErr != 0) { 92 sfree(defErr->message); 93 free(defErr); 94 } 95 } 96 97 static void 98 __initTsdKey(void) 99 { 100 (void) pthread_key_create(&tsdKey, __destroyTsdKey); 101 } 102 #pragma init(__initTsdKey) 103 104 void 105 reportError(int error, char *fmt, ...) { 106 __nis_deferred_error_t *defErr = pthread_getspecific(tsdKey); 107 int doStore = (defErr == 0); 108 char *myself = "reportError"; 109 va_list ap; 110 __nis_buffer_t b = {0, 0}; 111 112 if (defErr == 0 && (defErr = am(myself, sizeof (*defErr))) == 0) 113 return; 114 115 va_start(ap, fmt); 116 b.len = vp2buf(myself, &b.buf, b.len, fmt, ap); 117 va_end(ap); 118 119 if (b.len > 0) { 120 defErr->error = error; 121 defErr->message = b.buf; 122 if (doStore) { 123 int ret = pthread_setspecific(tsdKey, defErr); 124 if (ret != 0) { 125 logmsg(MSG_TSDERR, LOG_ERR, 126 "%s: pthread_setspecific() => %d", 127 myself, ret); 128 sfree(b.buf); 129 free(defErr); 130 } 131 } 132 } 133 } 134 135 int 136 getError(char **message) { 137 __nis_deferred_error_t *defErr = pthread_getspecific(tsdKey); 138 char *myself = "getError"; 139 140 if (defErr == 0) { 141 if (message != 0) 142 *message = sdup(myself, T, "no TSD"); 143 return (NPL_TSDERR); 144 } 145 146 if (message != 0) 147 *message = sdup(myself, T, defErr->message); 148 149 return (defErr->error); 150 } 151 152 void 153 clearError(void) { 154 __nis_deferred_error_t *defErr = pthread_getspecific(tsdKey); 155 156 if (defErr != 0) { 157 sfree(defErr->message); 158 defErr->message = 0; 159 defErr->error = NPL_NOERROR; 160 } 161 } 162 163 void 164 logError(int priority) { 165 __nis_deferred_error_t *defErr = pthread_getspecific(tsdKey); 166 int msgtype; 167 168 if (defErr != 0) { 169 switch (defErr->error) { 170 case NPL_NOERROR: 171 msgtype = MSG_LASTMSG; 172 break; 173 case NPL_NOMEM: 174 msgtype = MSG_NOMEM; 175 break; 176 case NPL_TSDERR: 177 msgtype = MSG_TSDERR; 178 break; 179 case NPL_BERENCODE: 180 case NPL_BERDECODE: 181 msgtype = MSG_BER; 182 break; 183 default: 184 msgtype = MSG_LASTMSG; 185 break; 186 } 187 188 if (msgtype != MSG_LASTMSG) { 189 logmsg(msgtype, priority, defErr->message); 190 } 191 } 192 } 193 194 /* 195 * Allocate zero-initialized memory of the specified 'size'. If the 196 * allocation fails, log a message and return NULL. Allocation of 197 * zero bytes is legal, and returns a NULL pointer. 198 */ 199 void * 200 am(const char *msg, int size) { 201 void *p; 202 203 if (size > 0) { 204 p = calloc(1, size); 205 if (p == 0) { 206 if (msg == 0) 207 msg = "<unknown>"; 208 logmsg(MSG_NOMEM, LOG_ERR, "%s: calloc(%d) => NULL\n", 209 msg, size); 210 return (0); 211 } 212 } else if (size == 0) { 213 p = 0; 214 } else { 215 if (msg == 0) 216 msg = "<unknown>"; 217 logmsg(MSG_MEMPARAM, LOG_INFO, "%s: size (%d) < 0\n", size); 218 exit(-1); 219 } 220 return (p); 221 } 222 223 /* 224 * Return the length of a string, just like strlen(), but don't croak 225 * on a NULL pointer. 226 */ 227 int 228 slen(const char *str) { 229 return ((str != 0) ? strlen(str) : 0); 230 } 231 232 /* 233 * If allocate==0, return 'str'; othewise, duplicate the string just 234 * like strdup(), but don't die if 'str' is a NULL pointer. 235 */ 236 char * 237 sdup(const char *msg, int allocate, char *str) { 238 char *s; 239 240 if (!allocate) 241 return (str); 242 243 if (str == 0) { 244 s = strdup(""); 245 } else { 246 s = strdup(str); 247 } 248 if (s == 0) { 249 logmsg(MSG_NOMEM, LOG_ERR, "%s: strdup(%d bytes) => NULL\n", 250 (msg != 0) ? msg : "<unknown>", slen(str)+1); 251 } 252 return (s); 253 } 254 255 /* 256 * Concatenate strings like strcat(), but don't expire if passed a 257 * NULL pointer or two. If deallocate!=0, free() the input strings. 258 */ 259 char * 260 scat(const char *msg, int deallocate, char *s1, char *s2) { 261 char *n; 262 int l1 = 0, l2 = 0; 263 264 if (s1 == 0) { 265 n = sdup(msg, T, s2); 266 if (deallocate) 267 sfree(s2); 268 return (n); 269 } else if (s2 == 0) { 270 n = sdup(msg, T, s1); 271 if (deallocate) 272 free(s1); 273 return (n); 274 } 275 276 l1 = strlen(s1); 277 l2 = strlen(s2); 278 279 n = malloc(l1+l2+1); 280 if (n != 0) { 281 memcpy(n, s1, l1); 282 memcpy(&n[l1], s2, l2); 283 n[l1+l2] = '\0'; 284 } else { 285 logmsg(MSG_NOMEM, LOG_ERR, "%s: malloc(%d) => NULL\n", 286 (msg != 0) ? msg : "<unknown>", l1+l2+1); 287 } 288 289 if (deallocate) { 290 free(s1); 291 free(s2); 292 } 293 294 return (n); 295 } 296 297 /* For debugging */ 298 static void *PTR = 0; 299 300 /* 301 * Counters for memory errors. Note that we don't protect access, 302 * so the values aren't entirely reliable in an MT application. 303 */ 304 ulong_t numMisaligned = 0; 305 ulong_t numNotActive = 0; 306 307 /* free() the input, but don't pass away if it's NULL */ 308 void 309 sfree(void *ptr) { 310 311 /* NULL pointer OK */ 312 if (ptr == 0) 313 return; 314 315 /* 316 * For use in the debugger, when we need to detect free of a 317 * certain address. 318 */ 319 if (ptr == PTR) 320 abort(); 321 322 /* 323 * All addresses returned by malloc() and friends are "suitably 324 * aligned for any use", so they should fall on eight-byte boundaries. 325 */ 326 if (((unsigned long)ptr % 8) != 0) { 327 numMisaligned++; 328 return; 329 } 330 331 #ifdef NISDB_LDAP_DEBUG 332 /* 333 * Malloc:ed memory should have the length (four bytes), starting 334 * eight bytes before the block, and with the least-significant 335 * bit set. 336 */ 337 if ((((uint_t *)ptr)[-2] & 0x1) == 0) { 338 numNotActive++; 339 return; 340 } 341 #endif /* NISDB_LDAP_DEBUG */ 342 343 /* Finally, we believe it's OK to free() the pointer */ 344 free(ptr); 345 } 346 347 /* 348 * If a __nis_single_value_t represents a string, the length count may or may 349 * not include a concluding NUL. Hence this function, which returns the last 350 * non-NUL character of the value. 351 */ 352 char 353 lastChar(__nis_single_value_t *v) { 354 char *s; 355 356 if (v == 0 || v->value == 0 || v->length < 2) 357 return ('\0'); 358 359 s = v->value; 360 if (s[v->length - 1] != '\0') 361 return (s[v->length - 1]); 362 else 363 return (s[v->length - 2]); 364 } 365 366 void * 367 appendString2SingleVal(char *str, __nis_single_value_t *v, int *newLen) { 368 void *s; 369 int l, nl; 370 char *myself = "appendString2SingleVal"; 371 372 if (v == 0 || v->length < 0) 373 return (0); 374 375 /* 376 * If 'str' is NULL or empty, just return NULL so that the caller 377 * does nothing. 378 */ 379 l = slen(str); 380 if (l <= 0) 381 return (0); 382 383 s = am(myself, (nl = l + v->length) + 1); 384 if (s == 0) { 385 /* Caller does nothing; let's hope for the best... */ 386 return (0); 387 } 388 389 if (v->value != 0) 390 memcpy(s, v->value, v->length); 391 392 memcpy(&(((char *)s)[v->length]), str, l); 393 394 if (newLen != 0) 395 *newLen = nl; 396 397 return (s); 398 } 399 400 401 /* 402 * Do the equivalent of a strcmp() between a string and a string-valued 403 * __nis_single_value_t. 404 */ 405 int 406 scmp(char *s, __nis_single_value_t *v) { 407 408 if (s == 0) 409 return (1); 410 else if (v == 0 || v->value == 0 || v->length <= 0) 411 return (-1); 412 413 return (strncmp(s, v->value, v->length)); 414 } 415 416 /* 417 * Do the equivalent of a strcasecmp() between a string and a string-valued 418 * __nis_single_value_t. 419 */ 420 int 421 scasecmp(char *s, __nis_single_value_t *v) { 422 423 if (s == 0) 424 return (1); 425 else if (v == 0 || v->value == 0 || v->length <= 0) 426 return (-1); 427 428 return (strncasecmp(s, v->value, v->length)); 429 } 430 431 #define STDBUFSIZE 81 432 433 /* 434 * vsprintf the 'fmt' and 'ap' to a buffer, then concatenate the 435 * result to '*buf'. 436 */ 437 int 438 vp2buf(const char *msg, char **buf, int buflen, const char *fmt, va_list ap) { 439 char *newbuf = am(msg, STDBUFSIZE); 440 int size = 0; 441 442 if (newbuf == 0) 443 return (0); 444 445 if (buf == 0 || buflen < 0 || fmt == 0) { 446 free(newbuf); 447 return (0); 448 } 449 450 /* Find out how large the new buffer needs to be */ 451 size = vsnprintf(newbuf, STDBUFSIZE, fmt, ap); 452 453 if (size > STDBUFSIZE) { 454 free(newbuf); 455 newbuf = am(msg, size+1); 456 if (newbuf == 0) 457 return (0); 458 size = vsnprintf(newbuf, size+1, fmt, ap); 459 } 460 461 *buf = scat(msg, T, *buf, newbuf); 462 /* Don't count the NUL. This enables us to concatenate correctly */ 463 buflen += size; 464 465 return (buflen); 466 } 467 468 /* Generic print buffer */ 469 __nis_buffer_t pb = {0, 0}; 470 471 /* sprintf to the generic __nis_buffer_t */ 472 void 473 p2buf(char *msg, char *fmt, ...) { 474 va_list ap; 475 476 va_start(ap, fmt); 477 pb.len = vp2buf(msg, &pb.buf, pb.len, fmt, ap); 478 va_end(ap); 479 } 480 481 /* sprintf to the specified __nis_buffer_t */ 482 void 483 bp2buf(const char *msg, __nis_buffer_t *b, const char *fmt, ...) { 484 va_list ap; 485 486 va_start(ap, fmt); 487 b->len = vp2buf(msg, &b->buf, b->len, fmt, ap); 488 va_end(ap); 489 } 490 491 /* Copy 'buf' to the specified __nis_buffer_t */ 492 void 493 bc2buf(const char *msg, void *buf, int len, __nis_buffer_t *b) { 494 void *new; 495 496 /* 497 * Make buffer one byte larger than the lenghts indicate. This 498 * gives us room to append a NUL, so that we can mix string and 499 * non-string copies into the buffer, and still end up with 500 * something that can be sent to printf(), strcat(), etc. 501 */ 502 new = realloc(b->buf, b->len+len+1); 503 if (new != 0) { 504 b->buf = new; 505 memcpy(&(b->buf[b->len]), buf, len); 506 b->len += len; 507 /* Put a NUL at the end, just in case we printf() */ 508 if (b->len > 0 && b->buf[b->len-1] != '\0') 509 b->buf[b->len] = '\0'; 510 } else { 511 logmsg(MSG_NOMEM, LOG_ERR, "%s: realloc(%d) => NULL\n", 512 (msg != 0) ? msg : "<unknown", b->len+len); 513 } 514 } 515 516 /* Like bc2buf(), but remove any trailing NUL bytes */ 517 void 518 sbc2buf(const char *msg, void *buf, int len, __nis_buffer_t *b) { 519 if (buf == 0 || len <= 0 || b == 0) 520 return; 521 /* Snip off trailing NULs */ 522 while (len > 0 && ((char *)buf)[len-1] == '\0') 523 len--; 524 if (len <= 0) 525 return; 526 bc2buf(msg, buf, len, b); 527 } 528 529 /* Copy 'buf' to the generic __nis_buffer_t */ 530 void 531 c2buf(char *msg, void *buf, int len) { 532 bc2buf(msg, buf, len, &pb); 533 } 534 535 /* Like c2buf(), but remove trailing NUL bytes */ 536 void 537 sc2buf(char *msg, void *buf, int len) { 538 sbc2buf(msg, buf, len, &pb); 539 } 540 541 /* How many times we try write(2) if it fails */ 542 #define MAXTRY 10 543 544 /* Output the generic __nis_buffer_t to stdout */ 545 void 546 printbuf(void) { 547 int maxtry = MAXTRY, len = pb.len; 548 549 if (pb.buf != 0) { 550 int tmp; 551 552 while (len > 0 && maxtry > 0) { 553 tmp = write(1, pb.buf, len); 554 if (tmp < 0) 555 break; 556 len -= tmp; 557 if (tmp > 0) 558 maxtry = MAXTRY; 559 else 560 maxtry--; 561 } 562 free(pb.buf); 563 pb.buf = 0; 564 } 565 pb.len = 0; 566 } 567 568 void * 569 extendArray(void *array, int newsize) { 570 void *new = realloc(array, newsize); 571 if (new == 0) 572 sfree(array); 573 return (new); 574 } 575 576 /* 577 * Determine if the given string is an IP address (IPv4 or IPv6). 578 * If so, it converts it to the format as required by rfc2307bis 579 * and *newaddr will point to the new Address. 580 * 581 * Returns -2 : error 582 * -1 : not an IP address 583 * 0 : IP address not supported by rfc2307bis 584 * AF_INET : IPv4 585 * AF_INET6 : IPv6 586 */ 587 int 588 checkIPaddress(char *addr, int len, char **newaddr) { 589 ipaddr_t addr_ipv4; 590 in6_addr_t addr_ipv6; 591 char *buffer; 592 int s, e; 593 char *myself = "checkIPaddress"; 594 595 /* skip leading whitespaces */ 596 for (s = 0; (s < len) && (addr[s] == ' ' || addr[s] == '\t'); s++); 597 if (s >= len) 598 return (-1); 599 600 /* skip trailing whitespaces */ 601 for (e = len - 1; (e > s) && (addr[e] == ' ' || addr[e] == '\t'); e--); 602 if (s == e) 603 return (-1); 604 605 /* adjust len */ 606 len = e - s + 1; 607 608 if ((buffer = am(myself, len + 1)) == 0) 609 return (-2); 610 (void) memcpy(buffer, addr + s, len); 611 612 if (inet_pton(AF_INET6, buffer, &addr_ipv6) == 1) { 613 sfree(buffer); 614 /* 615 * IPv4-compatible IPv6 address and IPv4-mapped 616 * IPv6 addresses not allowed by rfc2307bis 617 */ 618 if (IN6_IS_ADDR_V4COMPAT(&addr_ipv6)) 619 return (0); 620 if (IN6_IS_ADDR_V4MAPPED(&addr_ipv6)) 621 return (0); 622 if (newaddr == 0) 623 return (AF_INET6); 624 if ((*newaddr = am(myself, INET6_ADDRSTRLEN)) == 0) 625 return (-2); 626 if (inet_ntop(AF_INET6, &addr_ipv6, *newaddr, INET6_ADDRSTRLEN)) 627 return (AF_INET6); 628 sfree(*newaddr); 629 return (-2); 630 } 631 632 if (inet_pton(AF_INET, buffer, &addr_ipv4) == 1) { 633 sfree(buffer); 634 if (newaddr == 0) 635 return (AF_INET); 636 if ((*newaddr = am(myself, INET_ADDRSTRLEN)) == 0) 637 return (-2); 638 if (inet_ntop(AF_INET, &addr_ipv4, *newaddr, INET_ADDRSTRLEN)) 639 return (AF_INET); 640 sfree(*newaddr); 641 return (-2); 642 } 643 644 sfree(buffer); 645 return (-1); 646 } 647 648 int 649 sstrncmp(const char *s1, const char *s2, int n) { 650 if (s1 == 0 && s2 == 0) 651 return (0); 652 653 if (s1 == 0) 654 return (1); 655 656 if (s2 == 0) 657 return (-1); 658 659 return (strncmp(s1, s2, n)); 660 } 661 662 /* 663 * Does the following: 664 * - Trims leading and trailing whitespaces 665 * - Collapses two or more whitespaces into one space 666 * - Converts all whitespaces into spaces 667 * - At entrance, *len contains length of str 668 * - At exit, *len will contain length of the return string 669 * - In case of mem alloc failure, *len should be ignored 670 */ 671 char * 672 trimWhiteSpaces(char *str, int *len, int deallocate) { 673 char *ostr; 674 int olen = 0; 675 int first = 1, i; 676 char *myself = "trimWhiteSpaces"; 677 678 if ((ostr = am(myself, *len + 1)) == 0) { 679 if (deallocate) 680 sfree(str); 681 *len = 0; 682 return (0); 683 } 684 685 /* Skip leading whitespaces */ 686 for (i = 0; i < *len && (str[i] == ' ' || str[i] == '\t'); i++); 687 688 /* Collapse multiple whitespaces into one */ 689 for (; i < *len; i++) { 690 if (str[i] == ' ' || str[i] == '\t') { 691 if (first) { 692 first = 0; 693 ostr[olen++] = ' '; 694 } 695 continue; 696 } 697 first = 1; 698 ostr[olen++] = str[i]; 699 } 700 701 /* Handle the trailing whitespace if any */ 702 if (olen && ostr[olen - 1] == ' ') { 703 olen--; 704 ostr[olen] = 0; 705 } 706 707 if (deallocate) 708 sfree(str); 709 710 *len = olen; 711 return (ostr); 712 } 713 714 /* 715 * Escapes special characters in DN using the list from RFC 2253 716 */ 717 int 718 escapeSpecialChars(__nis_value_t *val) { 719 int i, j, k, count; 720 char *newval, *s; 721 char *myself = "escapeSpecialChars"; 722 723 /* Assume val is always non NULL */ 724 725 for (i = 0; i < val->numVals; i++) { 726 /* 727 * Count the special characters in value to determine 728 * the length for the new value 729 */ 730 s = val->val[i].value; 731 for (j = 0, count = 0; j < val->val[i].length; j++, s++) { 732 if (*s == '#' || *s == ',' || *s == '+' || *s == '"' || 733 *s == '\\' || *s == '<' || *s == '>' || *s == ';') 734 count++; 735 } 736 if (count == 0) 737 continue; 738 739 if ((newval = am(myself, val->val[i].length + count + 1)) == 0) 740 return (-1); 741 742 /* Escape the special characters using '\\' */ 743 s = val->val[i].value; 744 for (j = 0, k = 0; j < val->val[i].length; j++, k++, s++) { 745 if (*s == '#' || *s == ',' || *s == '+' || *s == '"' || 746 *s == '\\' || *s == '<' || *s == '>' || *s == ';') 747 newval[k++] = '\\'; 748 newval[k] = *s; 749 } 750 751 sfree(val->val[i].value); 752 val->val[i].value = newval; 753 val->val[i].length += count; 754 } 755 756 return (1); 757 } 758 759 /* 760 * Remove escape characters from DN returned by LDAP server 761 */ 762 void 763 removeEscapeChars(__nis_value_t *val) { 764 int i; 765 char *s, *d, *end; 766 767 768 for (i = 0; i < val->numVals; i++) { 769 s = val->val[i].value; 770 end = s + val->val[i].length; 771 772 /* 773 * This function is called frequently and for most entries 774 * there will be no escapes. Process rapidly up to first escape. 775 */ 776 for (d = s; s < end; s++, d++) { 777 if (*s == '\\') 778 break; 779 } 780 781 /* 782 * Reached the end, in which case will not go into loop, 783 * or found an escape and now have to start moving data. 784 */ 785 for (; s < end; s++) { 786 if (*s == '\\') { 787 val->val[i].length--; 788 /* 789 * Next character gets coppied without being 790 * checked 791 */ 792 s++; 793 if (s >= end) 794 break; 795 } 796 797 *d = *s; 798 d++; 799 } 800 } 801 } 802