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