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
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.
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]
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
33 #include <sys/types.h>
34 #include <sys/socket.h>
35 #include <netinet/in.h>
36 #include <arpa/inet.h>
38 #include "ldap_util.h"
39 #include "ldap_glob.h"
41 static time_t msgtime
[MSG_LASTMSG
] = {0};
42 static time_t msgtimeout
= 3600;
44 static pthread_key_t tsdKey
;
47 * Log a message to the appropriate place.
50 logmsg(int msgtype
, int priority
, const char *fmt
, ...) {
55 * Only log LOG_INFO priority if 'verbose' is on, or if
56 * msgtype is MSG_ALWAYS.
58 if (priority
== LOG_INFO
&& !verbose
&& msgtype
!= MSG_ALWAYS
)
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
)
67 msgtime
[msgtype
] = tp
.tv_sec
;
72 vsyslog(priority
, fmt
, ap
);
76 vfprintf(cons
, fmt
, ap
);
78 * If the last character in 'fmt' wasn't a '\n', write one
81 if (flen
> 0 && fmt
[flen
-1] != '\n')
88 __destroyTsdKey(void *arg
) {
89 __nis_deferred_error_t
*defErr
= arg
;
92 sfree(defErr
->message
);
100 (void) pthread_key_create(&tsdKey
, __destroyTsdKey
);
102 #pragma init(__initTsdKey)
105 reportError(int error
, char *fmt
, ...) {
106 __nis_deferred_error_t
*defErr
= pthread_getspecific(tsdKey
);
107 int doStore
= (defErr
== 0);
108 char *myself
= "reportError";
110 __nis_buffer_t b
= {0, 0};
112 if (defErr
== 0 && (defErr
= am(myself
, sizeof (*defErr
))) == 0)
116 b
.len
= vp2buf(myself
, &b
.buf
, b
.len
, fmt
, ap
);
120 defErr
->error
= error
;
121 defErr
->message
= b
.buf
;
123 int ret
= pthread_setspecific(tsdKey
, defErr
);
125 logmsg(MSG_TSDERR
, LOG_ERR
,
126 "%s: pthread_setspecific() => %d",
136 getError(char **message
) {
137 __nis_deferred_error_t
*defErr
= pthread_getspecific(tsdKey
);
138 char *myself
= "getError";
142 *message
= sdup(myself
, T
, "no TSD");
147 *message
= sdup(myself
, T
, defErr
->message
);
149 return (defErr
->error
);
154 __nis_deferred_error_t
*defErr
= pthread_getspecific(tsdKey
);
157 sfree(defErr
->message
);
159 defErr
->error
= NPL_NOERROR
;
164 logError(int priority
) {
165 __nis_deferred_error_t
*defErr
= pthread_getspecific(tsdKey
);
169 switch (defErr
->error
) {
171 msgtype
= MSG_LASTMSG
;
177 msgtype
= MSG_TSDERR
;
184 msgtype
= MSG_LASTMSG
;
188 if (msgtype
!= MSG_LASTMSG
) {
189 logmsg(msgtype
, priority
, defErr
->message
);
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.
200 am(const char *msg
, int size
) {
208 logmsg(MSG_NOMEM
, LOG_ERR
, "%s: calloc(%d) => NULL\n",
212 } else if (size
== 0) {
217 logmsg(MSG_MEMPARAM
, LOG_INFO
, "%s: size (%d) < 0\n", size
);
224 * Return the length of a string, just like strlen(), but don't croak
228 slen(const char *str
) {
229 return ((str
!= 0) ? strlen(str
) : 0);
233 * If allocate==0, return 'str'; othewise, duplicate the string just
234 * like strdup(), but don't die if 'str' is a NULL pointer.
237 sdup(const char *msg
, int allocate
, char *str
) {
249 logmsg(MSG_NOMEM
, LOG_ERR
, "%s: strdup(%d bytes) => NULL\n",
250 (msg
!= 0) ? msg
: "<unknown>", slen(str
)+1);
256 * Concatenate strings like strcat(), but don't expire if passed a
257 * NULL pointer or two. If deallocate!=0, free() the input strings.
260 scat(const char *msg
, int deallocate
, char *s1
, char *s2
) {
265 n
= sdup(msg
, T
, s2
);
269 } else if (s2
== 0) {
270 n
= sdup(msg
, T
, s1
);
282 memcpy(&n
[l1
], s2
, l2
);
285 logmsg(MSG_NOMEM
, LOG_ERR
, "%s: malloc(%d) => NULL\n",
286 (msg
!= 0) ? msg
: "<unknown>", l1
+l2
+1);
298 static void *PTR
= 0;
301 * Counters for memory errors. Note that we don't protect access,
302 * so the values aren't entirely reliable in an MT application.
304 ulong_t numMisaligned
= 0;
305 ulong_t numNotActive
= 0;
307 /* free() the input, but don't pass away if it's NULL */
311 /* NULL pointer OK */
316 * For use in the debugger, when we need to detect free of a
323 * All addresses returned by malloc() and friends are "suitably
324 * aligned for any use", so they should fall on eight-byte boundaries.
326 if (((unsigned long)ptr
% 8) != 0) {
331 #ifdef NISDB_LDAP_DEBUG
333 * Malloc:ed memory should have the length (four bytes), starting
334 * eight bytes before the block, and with the least-significant
337 if ((((uint_t
*)ptr
)[-2] & 0x1) == 0) {
341 #endif /* NISDB_LDAP_DEBUG */
343 /* Finally, we believe it's OK to free() the pointer */
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.
353 lastChar(__nis_single_value_t
*v
) {
356 if (v
== 0 || v
->value
== 0 || v
->length
< 2)
360 if (s
[v
->length
- 1] != '\0')
361 return (s
[v
->length
- 1]);
363 return (s
[v
->length
- 2]);
367 appendString2SingleVal(char *str
, __nis_single_value_t
*v
, int *newLen
) {
370 char *myself
= "appendString2SingleVal";
372 if (v
== 0 || v
->length
< 0)
376 * If 'str' is NULL or empty, just return NULL so that the caller
383 s
= am(myself
, (nl
= l
+ v
->length
) + 1);
385 /* Caller does nothing; let's hope for the best... */
390 memcpy(s
, v
->value
, v
->length
);
392 memcpy(&(((char *)s
)[v
->length
]), str
, l
);
402 * Do the equivalent of a strcmp() between a string and a string-valued
403 * __nis_single_value_t.
406 scmp(char *s
, __nis_single_value_t
*v
) {
410 else if (v
== 0 || v
->value
== 0 || v
->length
<= 0)
413 return (strncmp(s
, v
->value
, v
->length
));
417 * Do the equivalent of a strcasecmp() between a string and a string-valued
418 * __nis_single_value_t.
421 scasecmp(char *s
, __nis_single_value_t
*v
) {
425 else if (v
== 0 || v
->value
== 0 || v
->length
<= 0)
428 return (strncasecmp(s
, v
->value
, v
->length
));
431 #define STDBUFSIZE 81
434 * vsprintf the 'fmt' and 'ap' to a buffer, then concatenate the
438 vp2buf(const char *msg
, char **buf
, int buflen
, const char *fmt
, va_list ap
) {
439 char *newbuf
= am(msg
, STDBUFSIZE
);
445 if (buf
== 0 || buflen
< 0 || fmt
== 0) {
450 /* Find out how large the new buffer needs to be */
451 size
= vsnprintf(newbuf
, STDBUFSIZE
, fmt
, ap
);
453 if (size
> STDBUFSIZE
) {
455 newbuf
= am(msg
, size
+1);
458 size
= vsnprintf(newbuf
, size
+1, fmt
, ap
);
461 *buf
= scat(msg
, T
, *buf
, newbuf
);
462 /* Don't count the NUL. This enables us to concatenate correctly */
468 /* Generic print buffer */
469 __nis_buffer_t pb
= {0, 0};
471 /* sprintf to the generic __nis_buffer_t */
473 p2buf(char *msg
, char *fmt
, ...) {
477 pb
.len
= vp2buf(msg
, &pb
.buf
, pb
.len
, fmt
, ap
);
481 /* sprintf to the specified __nis_buffer_t */
483 bp2buf(const char *msg
, __nis_buffer_t
*b
, const char *fmt
, ...) {
487 b
->len
= vp2buf(msg
, &b
->buf
, b
->len
, fmt
, ap
);
491 /* Copy 'buf' to the specified __nis_buffer_t */
493 bc2buf(const char *msg
, void *buf
, int len
, __nis_buffer_t
*b
) {
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.
502 new = realloc(b
->buf
, b
->len
+len
+1);
505 memcpy(&(b
->buf
[b
->len
]), buf
, 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';
511 logmsg(MSG_NOMEM
, LOG_ERR
, "%s: realloc(%d) => NULL\n",
512 (msg
!= 0) ? msg
: "<unknown", b
->len
+len
);
516 /* Like bc2buf(), but remove any trailing NUL bytes */
518 sbc2buf(const char *msg
, void *buf
, int len
, __nis_buffer_t
*b
) {
519 if (buf
== 0 || len
<= 0 || b
== 0)
521 /* Snip off trailing NULs */
522 while (len
> 0 && ((char *)buf
)[len
-1] == '\0')
526 bc2buf(msg
, buf
, len
, b
);
529 /* Copy 'buf' to the generic __nis_buffer_t */
531 c2buf(char *msg
, void *buf
, int len
) {
532 bc2buf(msg
, buf
, len
, &pb
);
535 /* Like c2buf(), but remove trailing NUL bytes */
537 sc2buf(char *msg
, void *buf
, int len
) {
538 sbc2buf(msg
, buf
, len
, &pb
);
541 /* How many times we try write(2) if it fails */
544 /* Output the generic __nis_buffer_t to stdout */
547 int maxtry
= MAXTRY
, len
= pb
.len
;
552 while (len
> 0 && maxtry
> 0) {
553 tmp
= write(1, pb
.buf
, len
);
569 extendArray(void *array
, int newsize
) {
570 void *new = realloc(array
, newsize
);
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.
582 * -1 : not an IP address
583 * 0 : IP address not supported by rfc2307bis
588 checkIPaddress(char *addr
, int len
, char **newaddr
) {
590 in6_addr_t addr_ipv6
;
593 char *myself
= "checkIPaddress";
595 /* skip leading whitespaces */
596 for (s
= 0; (s
< len
) && (addr
[s
] == ' ' || addr
[s
] == '\t'); s
++);
600 /* skip trailing whitespaces */
601 for (e
= len
- 1; (e
> s
) && (addr
[e
] == ' ' || addr
[e
] == '\t'); e
--);
608 if ((buffer
= am(myself
, len
+ 1)) == 0)
610 (void) memcpy(buffer
, addr
+ s
, len
);
612 if (inet_pton(AF_INET6
, buffer
, &addr_ipv6
) == 1) {
615 * IPv4-compatible IPv6 address and IPv4-mapped
616 * IPv6 addresses not allowed by rfc2307bis
618 if (IN6_IS_ADDR_V4COMPAT(&addr_ipv6
))
620 if (IN6_IS_ADDR_V4MAPPED(&addr_ipv6
))
624 if ((*newaddr
= am(myself
, INET6_ADDRSTRLEN
)) == 0)
626 if (inet_ntop(AF_INET6
, &addr_ipv6
, *newaddr
, INET6_ADDRSTRLEN
))
632 if (inet_pton(AF_INET
, buffer
, &addr_ipv4
) == 1) {
636 if ((*newaddr
= am(myself
, INET_ADDRSTRLEN
)) == 0)
638 if (inet_ntop(AF_INET
, &addr_ipv4
, *newaddr
, INET_ADDRSTRLEN
))
649 sstrncmp(const char *s1
, const char *s2
, int n
) {
650 if (s1
== 0 && s2
== 0)
659 return (strncmp(s1
, s2
, n
));
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
672 trimWhiteSpaces(char *str
, int *len
, int deallocate
) {
676 char *myself
= "trimWhiteSpaces";
678 if ((ostr
= am(myself
, *len
+ 1)) == 0) {
685 /* Skip leading whitespaces */
686 for (i
= 0; i
< *len
&& (str
[i
] == ' ' || str
[i
] == '\t'); i
++);
688 /* Collapse multiple whitespaces into one */
689 for (; i
< *len
; i
++) {
690 if (str
[i
] == ' ' || str
[i
] == '\t') {
698 ostr
[olen
++] = str
[i
];
701 /* Handle the trailing whitespace if any */
702 if (olen
&& ostr
[olen
- 1] == ' ') {
715 * Escapes special characters in DN using the list from RFC 2253
718 escapeSpecialChars(__nis_value_t
*val
) {
721 char *myself
= "escapeSpecialChars";
723 /* Assume val is always non NULL */
725 for (i
= 0; i
< val
->numVals
; i
++) {
727 * Count the special characters in value to determine
728 * the length for the new value
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
== ';')
739 if ((newval
= am(myself
, val
->val
[i
].length
+ count
+ 1)) == 0)
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
== ';')
751 sfree(val
->val
[i
].value
);
752 val
->val
[i
].value
= newval
;
753 val
->val
[i
].length
+= count
;
760 * Remove escape characters from DN returned by LDAP server
763 removeEscapeChars(__nis_value_t
*val
) {
768 for (i
= 0; i
< val
->numVals
; i
++) {
769 s
= val
->val
[i
].value
;
770 end
= s
+ val
->val
[i
].length
;
773 * This function is called frequently and for most entries
774 * there will be no escapes. Process rapidly up to first escape.
776 for (d
= s
; s
< end
; s
++, d
++) {
782 * Reached the end, in which case will not go into loop,
783 * or found an escape and now have to start moving data.
785 for (; s
< end
; s
++) {
787 val
->val
[i
].length
--;
789 * Next character gets coppied without being