2N/A/*
2N/A * CDDL HEADER START
2N/A *
2N/A * The contents of this file are subject to the terms of the
2N/A * Common Development and Distribution License (the "License").
2N/A * You may not use this file except in compliance with the License.
2N/A *
2N/A * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
2N/A * or http://www.opensolaris.org/os/licensing.
2N/A * See the License for the specific language governing permissions
2N/A * and limitations under the License.
2N/A *
2N/A * When distributing Covered Code, include this CDDL HEADER in each
2N/A * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
2N/A * If applicable, add the following below this CDDL HEADER, with the
2N/A * fields enclosed by brackets "[]" replaced with your own identifying
2N/A * information: Portions Copyright [yyyy] [name of copyright owner]
2N/A *
2N/A * CDDL HEADER END
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2001, 2011, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include <stdio.h>
2N/A#include <stdlib.h>
2N/A#include <strings.h>
2N/A#include <string.h>
2N/A#include <unistd.h>
2N/A#include <pthread.h>
2N/A#include <sys/types.h>
2N/A#include <sys/socket.h>
2N/A#include <netinet/in.h>
2N/A#include <arpa/inet.h>
2N/A
2N/A#include "ldap_util.h"
2N/A#include "ldap_glob.h"
2N/A
2N/Astatic time_t msgtime[MSG_LASTMSG] = {0};
2N/Astatic time_t msgtimeout = 3600;
2N/A
2N/Astatic pthread_key_t tsdKey;
2N/A
2N/A/*
2N/A * Log a message to the appropriate place.
2N/A */
2N/Avoid
2N/Alogmsg(int msgtype, int priority, const char *fmt, ...) {
2N/A va_list ap;
2N/A struct timeval tp;
2N/A
2N/A /*
2N/A * Only log LOG_INFO priority if 'verbose' is on, or if
2N/A * msgtype is MSG_ALWAYS.
2N/A */
2N/A if (priority == LOG_INFO && !verbose && msgtype != MSG_ALWAYS)
2N/A return;
2N/A
2N/A /* Make sure we don't log the same message too often */
2N/A if (msgtype != MSG_NOTIMECHECK && msgtype != MSG_ALWAYS &&
2N/A msgtype > 0 && msgtype < MSG_LASTMSG &&
2N/A gettimeofday(&tp, 0) != -1) {
2N/A if (tp.tv_sec - msgtime[msgtype] < msgtimeout)
2N/A return;
2N/A msgtime[msgtype] = tp.tv_sec;
2N/A }
2N/A
2N/A va_start(ap, fmt);
2N/A if (cons == 0) {
2N/A vsyslog(priority, fmt, ap);
2N/A } else {
2N/A int flen = slen(fmt);
2N/A
2N/A vfprintf(cons, fmt, ap);
2N/A /*
2N/A * If the last character in 'fmt' wasn't a '\n', write one
2N/A * to the console.
2N/A */
2N/A if (flen > 0 && fmt[flen-1] != '\n')
2N/A fprintf(cons, "\n");
2N/A }
2N/A va_end(ap);
2N/A}
2N/A
2N/Avoid
2N/A__destroyTsdKey(void *arg) {
2N/A __nis_deferred_error_t *defErr = arg;
2N/A
2N/A if (defErr != 0) {
2N/A sfree(defErr->message);
2N/A free(defErr);
2N/A }
2N/A}
2N/A
2N/Astatic void
2N/A__initTsdKey(void)
2N/A{
2N/A (void) pthread_key_create(&tsdKey, __destroyTsdKey);
2N/A}
2N/A#pragma init(__initTsdKey)
2N/A
2N/Avoid
2N/AreportError(int error, char *fmt, ...) {
2N/A __nis_deferred_error_t *defErr = pthread_getspecific(tsdKey);
2N/A int doStore = (defErr == 0);
2N/A const char *myself = "reportError";
2N/A va_list ap;
2N/A __nis_buffer_t b = {0, 0};
2N/A
2N/A if (defErr == 0 && (defErr = am(myself, sizeof (*defErr))) == 0)
2N/A return;
2N/A
2N/A va_start(ap, fmt);
2N/A b.len = vp2buf(myself, &b.buf, b.len, fmt, ap);
2N/A va_end(ap);
2N/A
2N/A if (b.len > 0) {
2N/A defErr->error = error;
2N/A defErr->message = b.buf;
2N/A if (doStore) {
2N/A int ret = pthread_setspecific(tsdKey, defErr);
2N/A if (ret != 0) {
2N/A logmsg(MSG_TSDERR, LOG_ERR,
2N/A "%s: pthread_setspecific() => %d",
2N/A myself, ret);
2N/A sfree(b.buf);
2N/A free(defErr);
2N/A }
2N/A }
2N/A }
2N/A}
2N/A
2N/Aint
2N/AgetError(char **message) {
2N/A __nis_deferred_error_t *defErr = pthread_getspecific(tsdKey);
2N/A const char *myself = "getError";
2N/A
2N/A if (defErr == 0) {
2N/A if (message != 0)
2N/A *message = sdup(myself, T, "no TSD");
2N/A return (NPL_TSDERR);
2N/A }
2N/A
2N/A if (message != 0)
2N/A *message = sdup(myself, T, defErr->message);
2N/A
2N/A return (defErr->error);
2N/A}
2N/A
2N/Avoid
2N/AclearError(void) {
2N/A __nis_deferred_error_t *defErr = pthread_getspecific(tsdKey);
2N/A
2N/A if (defErr != 0) {
2N/A sfree(defErr->message);
2N/A defErr->message = 0;
2N/A defErr->error = NPL_NOERROR;
2N/A }
2N/A}
2N/A
2N/Avoid
2N/AlogError(int priority) {
2N/A __nis_deferred_error_t *defErr = pthread_getspecific(tsdKey);
2N/A int msgtype;
2N/A
2N/A if (defErr != 0) {
2N/A switch (defErr->error) {
2N/A case NPL_NOERROR:
2N/A msgtype = MSG_LASTMSG;
2N/A break;
2N/A case NPL_NOMEM:
2N/A msgtype = MSG_NOMEM;
2N/A break;
2N/A case NPL_TSDERR:
2N/A msgtype = MSG_TSDERR;
2N/A break;
2N/A case NPL_BERENCODE:
2N/A case NPL_BERDECODE:
2N/A msgtype = MSG_BER;
2N/A break;
2N/A default:
2N/A msgtype = MSG_LASTMSG;
2N/A break;
2N/A }
2N/A
2N/A if (msgtype != MSG_LASTMSG) {
2N/A logmsg(msgtype, priority, defErr->message);
2N/A }
2N/A }
2N/A}
2N/A
2N/A/*
2N/A * Allocate zero-initialized memory of the specified 'size'. If the
2N/A * allocation fails, log a message and return NULL. Allocation of
2N/A * zero bytes is legal, and returns a NULL pointer.
2N/A */
2N/Avoid *
2N/Aam(const char *msg, int size) {
2N/A void *p;
2N/A
2N/A if (size > 0) {
2N/A p = calloc(1, size);
2N/A if (p == 0) {
2N/A if (msg == 0)
2N/A msg = "<unknown>";
2N/A logmsg(MSG_NOMEM, LOG_ERR, "%s: calloc(%d) => NULL\n",
2N/A msg, size);
2N/A return (0);
2N/A }
2N/A } else if (size == 0) {
2N/A p = 0;
2N/A } else {
2N/A if (msg == 0)
2N/A msg = "<unknown>";
2N/A logmsg(MSG_MEMPARAM, LOG_INFO, "%s: size (%d) < 0\n", size);
2N/A exit(-1);
2N/A }
2N/A return (p);
2N/A}
2N/A
2N/A/*
2N/A * Return the length of a string, just like strlen(), but don't croak
2N/A * on a NULL pointer.
2N/A */
2N/Aint
2N/Aslen(const char *str) {
2N/A return ((str != NULL) ? strlen(str) : 0);
2N/A}
2N/A
2N/A/*
2N/A * If allocate==0, return 'str'; othewise, duplicate the string just
2N/A * like strdup(), but don't die if 'str' is a NULL pointer.
2N/A */
2N/Achar *
2N/Asdup(const char *msg, int allocate, char *str) {
2N/A char *s;
2N/A
2N/A if (!allocate)
2N/A return (str);
2N/A
2N/A if (str == 0) {
2N/A s = strdup("");
2N/A } else {
2N/A s = strdup(str);
2N/A }
2N/A if (s == 0) {
2N/A logmsg(MSG_NOMEM, LOG_ERR, "%s: strdup(%d bytes) => NULL\n",
2N/A (msg != 0) ? msg : "<unknown>", slen(str)+1);
2N/A }
2N/A return (s);
2N/A}
2N/A
2N/A/*
2N/A * Concatenate strings like strcat(), but don't expire if passed a
2N/A * NULL pointer or two. If deallocate!=0, free() the input strings.
2N/A */
2N/Achar *
2N/Ascat(const char *msg, int deallocate, char *s1, char *s2) {
2N/A char *n;
2N/A int l1 = 0, l2 = 0;
2N/A
2N/A if (s1 == 0) {
2N/A n = sdup(msg, T, s2);
2N/A if (deallocate)
2N/A sfree(s2);
2N/A return (n);
2N/A } else if (s2 == 0) {
2N/A n = sdup(msg, T, s1);
2N/A if (deallocate)
2N/A free(s1);
2N/A return (n);
2N/A }
2N/A
2N/A l1 = strlen(s1);
2N/A l2 = strlen(s2);
2N/A
2N/A n = malloc(l1+l2+1);
2N/A if (n != 0) {
2N/A memcpy(n, s1, l1);
2N/A memcpy(&n[l1], s2, l2);
2N/A n[l1+l2] = '\0';
2N/A } else {
2N/A logmsg(MSG_NOMEM, LOG_ERR, "%s: malloc(%d) => NULL\n",
2N/A (msg != 0) ? msg : "<unknown>", l1+l2+1);
2N/A }
2N/A
2N/A if (deallocate) {
2N/A free(s1);
2N/A free(s2);
2N/A }
2N/A
2N/A return (n);
2N/A}
2N/A
2N/A/* For debugging */
2N/Astatic void *PTR = 0;
2N/A
2N/A/*
2N/A * Counters for memory errors. Note that we don't protect access,
2N/A * so the values aren't entirely reliable in an MT application.
2N/A */
2N/Aulong_t numMisaligned = 0;
2N/Aulong_t numNotActive = 0;
2N/A
2N/A/* free() the input, but don't pass away if it's NULL */
2N/Avoid
2N/Asfree(void *ptr) {
2N/A
2N/A /* NULL pointer OK */
2N/A if (ptr == 0)
2N/A return;
2N/A
2N/A /*
2N/A * For use in the debugger, when we need to detect free of a
2N/A * certain address.
2N/A */
2N/A if (ptr == PTR)
2N/A abort();
2N/A
2N/A /*
2N/A * All addresses returned by malloc() and friends are "suitably
2N/A * aligned for any use", so they should fall on eight-byte boundaries.
2N/A */
2N/A if (((unsigned long)ptr % 8) != 0) {
2N/A numMisaligned++;
2N/A return;
2N/A }
2N/A
2N/A#ifdef NISDB_LDAP_DEBUG
2N/A /*
2N/A * Malloc:ed memory should have the length (four bytes), starting
2N/A * eight bytes before the block, and with the least-significant
2N/A * bit set.
2N/A */
2N/A if ((((uint_t *)ptr)[-2] & 0x1) == 0) {
2N/A numNotActive++;
2N/A return;
2N/A }
2N/A#endif /* NISDB_LDAP_DEBUG */
2N/A
2N/A /* Finally, we believe it's OK to free() the pointer */
2N/A free(ptr);
2N/A}
2N/A
2N/A/*
2N/A * If a __nis_single_value_t represents a string, the length count may or may
2N/A * not include a concluding NUL. Hence this function, which returns the last
2N/A * non-NUL character of the value.
2N/A */
2N/Achar
2N/AlastChar(__nis_single_value_t *v) {
2N/A char *s;
2N/A
2N/A if (v == 0 || v->value == 0 || v->length < 2)
2N/A return ('\0');
2N/A
2N/A s = v->value;
2N/A if (s[v->length - 1] != '\0')
2N/A return (s[v->length - 1]);
2N/A else
2N/A return (s[v->length - 2]);
2N/A}
2N/A
2N/Avoid *
2N/AappendString2SingleVal(char *str, __nis_single_value_t *v, int *newLen) {
2N/A void *s;
2N/A int l, nl;
2N/A const char *myself = "appendString2SingleVal";
2N/A
2N/A if (v == 0 || v->length < 0)
2N/A return (0);
2N/A
2N/A /*
2N/A * If 'str' is NULL or empty, just return NULL so that the caller
2N/A * does nothing.
2N/A */
2N/A l = slen(str);
2N/A if (l <= 0)
2N/A return (0);
2N/A
2N/A s = am(myself, (nl = l + v->length) + 1);
2N/A if (s == 0) {
2N/A /* Caller does nothing; let's hope for the best... */
2N/A return (0);
2N/A }
2N/A
2N/A if (v->value != 0)
2N/A memcpy(s, v->value, v->length);
2N/A
2N/A memcpy(&(((char *)s)[v->length]), str, l);
2N/A
2N/A if (newLen != 0)
2N/A *newLen = nl;
2N/A
2N/A return (s);
2N/A}
2N/A
2N/A
2N/A/*
2N/A * Do the equivalent of a strcmp() between a string and a string-valued
2N/A * __nis_single_value_t.
2N/A */
2N/Aint
2N/Ascmp(char *s, __nis_single_value_t *v) {
2N/A
2N/A if (s == 0)
2N/A return (1);
2N/A else if (v == 0 || v->value == 0 || v->length <= 0)
2N/A return (-1);
2N/A
2N/A return (strncmp(s, v->value, v->length));
2N/A}
2N/A
2N/A/*
2N/A * Do the equivalent of a strcasecmp() between a string and a string-valued
2N/A * __nis_single_value_t.
2N/A */
2N/Aint
2N/Ascasecmp(char *s, __nis_single_value_t *v) {
2N/A
2N/A if (s == 0)
2N/A return (1);
2N/A else if (v == 0 || v->value == 0 || v->length <= 0)
2N/A return (-1);
2N/A
2N/A return (strncasecmp(s, v->value, v->length));
2N/A}
2N/A
2N/A#define STDBUFSIZE 81
2N/A
2N/A/*
2N/A * vsprintf the 'fmt' and 'ap' to a buffer, then concatenate the
2N/A * result to '*buf'.
2N/A */
2N/Aint
2N/Avp2buf(const char *msg, char **buf, int buflen, const char *fmt, va_list ap) {
2N/A char *newbuf = am(msg, STDBUFSIZE);
2N/A int size = 0;
2N/A
2N/A if (newbuf == 0)
2N/A return (0);
2N/A
2N/A if (buf == 0 || buflen < 0 || fmt == 0) {
2N/A free(newbuf);
2N/A return (0);
2N/A }
2N/A
2N/A /* Find out how large the new buffer needs to be */
2N/A size = vsnprintf(newbuf, STDBUFSIZE, fmt, ap);
2N/A
2N/A if (size > STDBUFSIZE) {
2N/A free(newbuf);
2N/A newbuf = am(msg, size+1);
2N/A if (newbuf == 0)
2N/A return (0);
2N/A size = vsnprintf(newbuf, size+1, fmt, ap);
2N/A }
2N/A
2N/A *buf = scat(msg, T, *buf, newbuf);
2N/A /* Don't count the NUL. This enables us to concatenate correctly */
2N/A buflen += size;
2N/A
2N/A return (buflen);
2N/A}
2N/A
2N/A/* Generic print buffer */
2N/A__nis_buffer_t pb = {0, 0};
2N/A
2N/A/* sprintf to the generic __nis_buffer_t */
2N/Avoid
2N/Ap2buf(const char *msg, char *fmt, ...) {
2N/A va_list ap;
2N/A
2N/A va_start(ap, fmt);
2N/A pb.len = vp2buf(msg, &pb.buf, pb.len, fmt, ap);
2N/A va_end(ap);
2N/A}
2N/A
2N/A/* sprintf to the specified __nis_buffer_t */
2N/Avoid
2N/Abp2buf(const char *msg, __nis_buffer_t *b, const char *fmt, ...) {
2N/A va_list ap;
2N/A
2N/A va_start(ap, fmt);
2N/A b->len = vp2buf(msg, &b->buf, b->len, fmt, ap);
2N/A va_end(ap);
2N/A}
2N/A
2N/A/* Copy 'buf' to the specified __nis_buffer_t */
2N/Avoid
2N/Abc2buf(const char *msg, void *buf, int len, __nis_buffer_t *b) {
2N/A void *new;
2N/A
2N/A /*
2N/A * Make buffer one byte larger than the lengths indicate. This
2N/A * gives us room to append a NUL, so that we can mix string and
2N/A * non-string copies into the buffer, and still end up with
2N/A * something that can be sent to printf(), strcat(), etc.
2N/A */
2N/A new = realloc(b->buf, b->len+len+1);
2N/A if (new != 0) {
2N/A b->buf = new;
2N/A memcpy(&(b->buf[b->len]), buf, len);
2N/A b->len += len;
2N/A /* Put a NUL at the end, just in case we printf() */
2N/A if (b->len > 0 && b->buf[b->len-1] != '\0')
2N/A b->buf[b->len] = '\0';
2N/A } else {
2N/A logmsg(MSG_NOMEM, LOG_ERR, "%s: realloc(%d) => NULL\n",
2N/A (msg != 0) ? msg : "<unknown", b->len+len);
2N/A }
2N/A}
2N/A
2N/A/* Like bc2buf(), but remove any trailing NUL bytes */
2N/Avoid
2N/Asbc2buf(const char *msg, void *buf, int len, __nis_buffer_t *b) {
2N/A if (buf == 0 || len <= 0 || b == 0)
2N/A return;
2N/A /* Snip off trailing NULs */
2N/A while (len > 0 && ((char *)buf)[len-1] == '\0')
2N/A len--;
2N/A if (len <= 0)
2N/A return;
2N/A bc2buf(msg, buf, len, b);
2N/A}
2N/A
2N/A/* Copy 'buf' to the generic __nis_buffer_t */
2N/Avoid
2N/Ac2buf(const char *msg, void *buf, int len) {
2N/A bc2buf(msg, buf, len, &pb);
2N/A}
2N/A
2N/A/* Like c2buf(), but remove trailing NUL bytes */
2N/Avoid
2N/Asc2buf(const char *msg, void *buf, int len) {
2N/A sbc2buf(msg, buf, len, &pb);
2N/A}
2N/A
2N/A/* How many times we try write(2) if it fails */
2N/A#define MAXTRY 10
2N/A
2N/A/* Output the generic __nis_buffer_t to stdout */
2N/Avoid
2N/Aprintbuf(void) {
2N/A int maxtry = MAXTRY, len = pb.len;
2N/A
2N/A if (pb.buf != 0) {
2N/A int tmp;
2N/A
2N/A while (len > 0 && maxtry > 0) {
2N/A tmp = write(1, pb.buf, len);
2N/A if (tmp < 0)
2N/A break;
2N/A len -= tmp;
2N/A if (tmp > 0)
2N/A maxtry = MAXTRY;
2N/A else
2N/A maxtry--;
2N/A }
2N/A free(pb.buf);
2N/A pb.buf = 0;
2N/A }
2N/A pb.len = 0;
2N/A}
2N/A
2N/Avoid *
2N/AextendArray(void *array, int newsize) {
2N/A void *new = realloc(array, newsize);
2N/A if (new == 0)
2N/A sfree(array);
2N/A return (new);
2N/A}
2N/A
2N/A/*
2N/A * Determine if the given string is an IP address (IPv4 or IPv6).
2N/A * If so, it converts it to the format as required by rfc2307bis
2N/A * and *newaddr will point to the new Address.
2N/A *
2N/A * Returns -2 : error
2N/A * -1 : not an IP address
2N/A * 0 : IP address not supported by rfc2307bis
2N/A * AF_INET : IPv4
2N/A * AF_INET6 : IPv6
2N/A */
2N/Aint
2N/AcheckIPaddress(char *addr, int len, char **newaddr) {
2N/A ipaddr_t addr_ipv4;
2N/A in6_addr_t addr_ipv6;
2N/A char *buffer;
2N/A int s, e;
2N/A const char *myself = "checkIPaddress";
2N/A
2N/A /* skip leading whitespaces */
2N/A for (s = 0; (s < len) && (addr[s] == ' ' || addr[s] == '\t'); s++);
2N/A if (s >= len)
2N/A return (-1);
2N/A
2N/A /* skip trailing whitespaces */
2N/A for (e = len - 1; (e > s) && (addr[e] == ' ' || addr[e] == '\t'); e--);
2N/A if (s == e)
2N/A return (-1);
2N/A
2N/A /* adjust len */
2N/A len = e - s + 1;
2N/A
2N/A if ((buffer = am(myself, len + 1)) == 0)
2N/A return (-2);
2N/A (void) memcpy(buffer, addr + s, len);
2N/A
2N/A if (inet_pton(AF_INET6, buffer, &addr_ipv6) == 1) {
2N/A sfree(buffer);
2N/A /*
2N/A * IPv4-compatible IPv6 address and IPv4-mapped
2N/A * IPv6 addresses not allowed by rfc2307bis
2N/A */
2N/A if (IN6_IS_ADDR_V4COMPAT(&addr_ipv6))
2N/A return (0);
2N/A if (IN6_IS_ADDR_V4MAPPED(&addr_ipv6))
2N/A return (0);
2N/A if (newaddr == 0)
2N/A return (AF_INET6);
2N/A if ((*newaddr = am(myself, INET6_ADDRSTRLEN)) == 0)
2N/A return (-2);
2N/A if (inet_ntop(AF_INET6, &addr_ipv6, *newaddr, INET6_ADDRSTRLEN))
2N/A return (AF_INET6);
2N/A sfree(*newaddr);
2N/A return (-2);
2N/A }
2N/A
2N/A if (inet_pton(AF_INET, buffer, &addr_ipv4) == 1) {
2N/A sfree(buffer);
2N/A if (newaddr == 0)
2N/A return (AF_INET);
2N/A if ((*newaddr = am(myself, INET_ADDRSTRLEN)) == 0)
2N/A return (-2);
2N/A if (inet_ntop(AF_INET, &addr_ipv4, *newaddr, INET_ADDRSTRLEN))
2N/A return (AF_INET);
2N/A sfree(*newaddr);
2N/A return (-2);
2N/A }
2N/A
2N/A sfree(buffer);
2N/A return (-1);
2N/A}
2N/A
2N/Aint
2N/Asstrncmp(const char *s1, const char *s2, int n) {
2N/A if (s1 == 0 && s2 == 0)
2N/A return (0);
2N/A
2N/A if (s1 == 0)
2N/A return (1);
2N/A
2N/A if (s2 == 0)
2N/A return (-1);
2N/A
2N/A return (strncmp(s1, s2, n));
2N/A}
2N/A
2N/A/*
2N/A * Does the following:
2N/A * - Trims leading and trailing whitespaces
2N/A * - Collapses two or more whitespaces into one space
2N/A * - Converts all whitespaces into spaces
2N/A * - At entrance, *len contains length of str
2N/A * - At exit, *len will contain length of the return string
2N/A * - In case of mem alloc failure, *len should be ignored
2N/A */
2N/Achar *
2N/AtrimWhiteSpaces(char *str, int *len, int deallocate) {
2N/A char *ostr;
2N/A int olen = 0;
2N/A int first = 1, i;
2N/A const char *myself = "trimWhiteSpaces";
2N/A
2N/A if ((ostr = am(myself, *len + 1)) == 0) {
2N/A if (deallocate)
2N/A sfree(str);
2N/A *len = 0;
2N/A return (0);
2N/A }
2N/A
2N/A /* Skip leading whitespaces */
2N/A for (i = 0; i < *len && (str[i] == ' ' || str[i] == '\t'); i++);
2N/A
2N/A /* Collapse multiple whitespaces into one */
2N/A for (; i < *len; i++) {
2N/A if (str[i] == ' ' || str[i] == '\t') {
2N/A if (first) {
2N/A first = 0;
2N/A ostr[olen++] = ' ';
2N/A }
2N/A continue;
2N/A }
2N/A first = 1;
2N/A ostr[olen++] = str[i];
2N/A }
2N/A
2N/A /* Handle the trailing whitespace if any */
2N/A if (olen && ostr[olen - 1] == ' ') {
2N/A olen--;
2N/A ostr[olen] = 0;
2N/A }
2N/A
2N/A if (deallocate)
2N/A sfree(str);
2N/A
2N/A *len = olen;
2N/A return (ostr);
2N/A}
2N/A
2N/A/*
2N/A * Escapes special characters in DN using the list from RFC 2253
2N/A */
2N/Aint
2N/AescapeSpecialChars(__nis_value_t *val) {
2N/A int i, j, k, count;
2N/A char *newval, *s;
2N/A const char *myself = "escapeSpecialChars";
2N/A
2N/A /* Assume val is always non NULL */
2N/A
2N/A for (i = 0; i < val->numVals; i++) {
2N/A /*
2N/A * Count the special characters in value to determine
2N/A * the length for the new value
2N/A */
2N/A s = val->val[i].value;
2N/A for (j = 0, count = 0; j < val->val[i].length; j++, s++) {
2N/A if (*s == '#' || *s == ',' || *s == '+' || *s == '"' ||
2N/A *s == '\\' || *s == '<' || *s == '>' || *s == ';')
2N/A count++;
2N/A }
2N/A if (count == 0)
2N/A continue;
2N/A
2N/A if ((newval = am(myself, val->val[i].length + count + 1)) == 0)
2N/A return (-1);
2N/A
2N/A /* Escape the special characters using '\\' */
2N/A s = val->val[i].value;
2N/A for (j = 0, k = 0; j < val->val[i].length; j++, k++, s++) {
2N/A if (*s == '#' || *s == ',' || *s == '+' || *s == '"' ||
2N/A *s == '\\' || *s == '<' || *s == '>' || *s == ';')
2N/A newval[k++] = '\\';
2N/A newval[k] = *s;
2N/A }
2N/A
2N/A sfree(val->val[i].value);
2N/A val->val[i].value = newval;
2N/A val->val[i].length += count;
2N/A }
2N/A
2N/A return (1);
2N/A}
2N/A
2N/A/*
2N/A * Remove escape characters from DN returned by LDAP server
2N/A */
2N/Avoid
2N/AremoveEscapeChars(__nis_value_t *val) {
2N/A int i;
2N/A char *s, *d, *end;
2N/A
2N/A
2N/A for (i = 0; i < val->numVals; i++) {
2N/A s = val->val[i].value;
2N/A end = s + val->val[i].length;
2N/A
2N/A /*
2N/A * This function is called frequently and for most entries
2N/A * there will be no escapes. Process rapidly up to first escape.
2N/A */
2N/A for (d = s; s < end; s++, d++) {
2N/A if (*s == '\\')
2N/A break;
2N/A }
2N/A
2N/A /*
2N/A * Reached the end, in which case will not go into loop,
2N/A * or found an escape and now have to start moving data.
2N/A */
2N/A for (; s < end; s++) {
2N/A if (*s == '\\') {
2N/A val->val[i].length--;
2N/A /*
2N/A * Next character gets coppied without being
2N/A * checked
2N/A */
2N/A s++;
2N/A if (s >= end)
2N/A break;
2N/A }
2N/A
2N/A *d = *s;
2N/A d++;
2N/A }
2N/A }
2N/A}