#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include "ldap_util.h"
#include "ldap_glob.h"
static time_t msgtime[MSG_LASTMSG] = {0};
static time_t msgtimeout = 3600;
static pthread_key_t tsdKey;
void
logmsg(int msgtype, int priority, const char *fmt, ...) {
va_list ap;
struct timeval tp;
if (priority == LOG_INFO && !verbose && msgtype != MSG_ALWAYS)
return;
if (msgtype != MSG_NOTIMECHECK && msgtype != MSG_ALWAYS &&
msgtype > 0 && msgtype < MSG_LASTMSG &&
gettimeofday(&tp, 0) != -1) {
if (tp.tv_sec - msgtime[msgtype] < msgtimeout)
return;
msgtime[msgtype] = tp.tv_sec;
}
va_start(ap, fmt);
if (cons == 0) {
vsyslog(priority, fmt, ap);
} else {
int flen = slen(fmt);
vfprintf(cons, fmt, ap);
if (flen > 0 && fmt[flen-1] != '\n')
fprintf(cons, "\n");
}
va_end(ap);
}
void
__destroyTsdKey(void *arg) {
__nis_deferred_error_t *defErr = arg;
if (defErr != 0) {
sfree(defErr->message);
free(defErr);
}
}
static void
__initTsdKey(void)
{
(void) pthread_key_create(&tsdKey, __destroyTsdKey);
}
#pragma init(__initTsdKey)
void
reportError(int error, char *fmt, ...) {
__nis_deferred_error_t *defErr = pthread_getspecific(tsdKey);
int doStore = (defErr == 0);
char *myself = "reportError";
va_list ap;
__nis_buffer_t b = {0, 0};
if (defErr == 0 && (defErr = am(myself, sizeof (*defErr))) == 0)
return;
va_start(ap, fmt);
b.len = vp2buf(myself, &b.buf, b.len, fmt, ap);
va_end(ap);
if (b.len > 0) {
defErr->error = error;
defErr->message = b.buf;
if (doStore) {
int ret = pthread_setspecific(tsdKey, defErr);
if (ret != 0) {
logmsg(MSG_TSDERR, LOG_ERR,
"%s: pthread_setspecific() => %d",
myself, ret);
sfree(b.buf);
free(defErr);
}
}
}
}
int
getError(char **message) {
__nis_deferred_error_t *defErr = pthread_getspecific(tsdKey);
char *myself = "getError";
if (defErr == 0) {
if (message != 0)
*message = sdup(myself, T, "no TSD");
return (NPL_TSDERR);
}
if (message != 0)
*message = sdup(myself, T, defErr->message);
return (defErr->error);
}
void
clearError(void) {
__nis_deferred_error_t *defErr = pthread_getspecific(tsdKey);
if (defErr != 0) {
sfree(defErr->message);
defErr->message = 0;
defErr->error = NPL_NOERROR;
}
}
void
logError(int priority) {
__nis_deferred_error_t *defErr = pthread_getspecific(tsdKey);
int msgtype;
if (defErr != 0) {
switch (defErr->error) {
case NPL_NOERROR:
msgtype = MSG_LASTMSG;
break;
case NPL_NOMEM:
msgtype = MSG_NOMEM;
break;
case NPL_TSDERR:
msgtype = MSG_TSDERR;
break;
case NPL_BERENCODE:
case NPL_BERDECODE:
msgtype = MSG_BER;
break;
default:
msgtype = MSG_LASTMSG;
break;
}
if (msgtype != MSG_LASTMSG) {
logmsg(msgtype, priority, defErr->message);
}
}
}
void *
am(const char *msg, int size) {
void *p;
if (size > 0) {
p = calloc(1, size);
if (p == 0) {
if (msg == 0)
msg = "<unknown>";
logmsg(MSG_NOMEM, LOG_ERR, "%s: calloc(%d) => NULL\n",
msg, size);
return (0);
}
} else if (size == 0) {
p = 0;
} else {
if (msg == 0)
msg = "<unknown>";
logmsg(MSG_MEMPARAM, LOG_INFO, "%s: size (%d) < 0\n", size);
exit(-1);
}
return (p);
}
int
slen(const char *str) {
return ((str != 0) ? strlen(str) : 0);
}
char *
sdup(const char *msg, int allocate, char *str) {
char *s;
if (!allocate)
return (str);
if (str == 0) {
s = strdup("");
} else {
s = strdup(str);
}
if (s == 0) {
logmsg(MSG_NOMEM, LOG_ERR, "%s: strdup(%d bytes) => NULL\n",
(msg != 0) ? msg : "<unknown>", slen(str)+1);
}
return (s);
}
char *
scat(const char *msg, int deallocate, char *s1, char *s2) {
char *n;
int l1 = 0, l2 = 0;
if (s1 == 0) {
n = sdup(msg, T, s2);
if (deallocate)
sfree(s2);
return (n);
} else if (s2 == 0) {
n = sdup(msg, T, s1);
if (deallocate)
free(s1);
return (n);
}
l1 = strlen(s1);
l2 = strlen(s2);
n = malloc(l1+l2+1);
if (n != 0) {
memcpy(n, s1, l1);
memcpy(&n[l1], s2, l2);
n[l1+l2] = '\0';
} else {
logmsg(MSG_NOMEM, LOG_ERR, "%s: malloc(%d) => NULL\n",
(msg != 0) ? msg : "<unknown>", l1+l2+1);
}
if (deallocate) {
free(s1);
free(s2);
}
return (n);
}
static void *PTR = 0;
ulong_t numMisaligned = 0;
ulong_t numNotActive = 0;
void
sfree(void *ptr) {
if (ptr == 0)
return;
if (ptr == PTR)
abort();
if (((unsigned long)ptr % 8) != 0) {
numMisaligned++;
return;
}
#ifdef NISDB_LDAP_DEBUG
if ((((uint_t *)ptr)[-2] & 0x1) == 0) {
numNotActive++;
return;
}
#endif
free(ptr);
}
char
lastChar(__nis_single_value_t *v) {
char *s;
if (v == 0 || v->value == 0 || v->length < 2)
return ('\0');
s = v->value;
if (s[v->length - 1] != '\0')
return (s[v->length - 1]);
else
return (s[v->length - 2]);
}
void *
appendString2SingleVal(char *str, __nis_single_value_t *v, int *newLen) {
void *s;
int l, nl;
char *myself = "appendString2SingleVal";
if (v == 0 || v->length < 0)
return (0);
l = slen(str);
if (l <= 0)
return (0);
s = am(myself, (nl = l + v->length) + 1);
if (s == 0) {
return (0);
}
if (v->value != 0)
memcpy(s, v->value, v->length);
memcpy(&(((char *)s)[v->length]), str, l);
if (newLen != 0)
*newLen = nl;
return (s);
}
int
scmp(char *s, __nis_single_value_t *v) {
if (s == 0)
return (1);
else if (v == 0 || v->value == 0 || v->length <= 0)
return (-1);
return (strncmp(s, v->value, v->length));
}
int
scasecmp(char *s, __nis_single_value_t *v) {
if (s == 0)
return (1);
else if (v == 0 || v->value == 0 || v->length <= 0)
return (-1);
return (strncasecmp(s, v->value, v->length));
}
#define STDBUFSIZE 81
int
vp2buf(const char *msg, char **buf, int buflen, const char *fmt, va_list ap) {
char *newbuf = am(msg, STDBUFSIZE);
int size = 0;
if (newbuf == 0)
return (0);
if (buf == 0 || buflen < 0 || fmt == 0) {
free(newbuf);
return (0);
}
size = vsnprintf(newbuf, STDBUFSIZE, fmt, ap);
if (size > STDBUFSIZE) {
free(newbuf);
newbuf = am(msg, size+1);
if (newbuf == 0)
return (0);
size = vsnprintf(newbuf, size+1, fmt, ap);
}
*buf = scat(msg, T, *buf, newbuf);
buflen += size;
return (buflen);
}
__nis_buffer_t pb = {0, 0};
void
p2buf(char *msg, char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
pb.len = vp2buf(msg, &pb.buf, pb.len, fmt, ap);
va_end(ap);
}
void
bp2buf(const char *msg, __nis_buffer_t *b, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
b->len = vp2buf(msg, &b->buf, b->len, fmt, ap);
va_end(ap);
}
void
bc2buf(const char *msg, void *buf, int len, __nis_buffer_t *b) {
void *new;
new = realloc(b->buf, b->len+len+1);
if (new != 0) {
b->buf = new;
memcpy(&(b->buf[b->len]), buf, len);
b->len += len;
if (b->len > 0 && b->buf[b->len-1] != '\0')
b->buf[b->len] = '\0';
} else {
logmsg(MSG_NOMEM, LOG_ERR, "%s: realloc(%d) => NULL\n",
(msg != 0) ? msg : "<unknown", b->len+len);
}
}
void
sbc2buf(const char *msg, void *buf, int len, __nis_buffer_t *b) {
if (buf == 0 || len <= 0 || b == 0)
return;
while (len > 0 && ((char *)buf)[len-1] == '\0')
len--;
if (len <= 0)
return;
bc2buf(msg, buf, len, b);
}
void
c2buf(char *msg, void *buf, int len) {
bc2buf(msg, buf, len, &pb);
}
void
sc2buf(char *msg, void *buf, int len) {
sbc2buf(msg, buf, len, &pb);
}
#define MAXTRY 10
void
printbuf(void) {
int maxtry = MAXTRY, len = pb.len;
if (pb.buf != 0) {
int tmp;
while (len > 0 && maxtry > 0) {
tmp = write(1, pb.buf, len);
if (tmp < 0)
break;
len -= tmp;
if (tmp > 0)
maxtry = MAXTRY;
else
maxtry--;
}
free(pb.buf);
pb.buf = 0;
}
pb.len = 0;
}
void *
extendArray(void *array, int newsize) {
void *new = realloc(array, newsize);
if (new == 0)
sfree(array);
return (new);
}
int
checkIPaddress(char *addr, int len, char **newaddr) {
ipaddr_t addr_ipv4;
in6_addr_t addr_ipv6;
char *buffer;
int s, e;
char *myself = "checkIPaddress";
for (s = 0; (s < len) && (addr[s] == ' ' || addr[s] == '\t'); s++);
if (s >= len)
return (-1);
for (e = len - 1; (e > s) && (addr[e] == ' ' || addr[e] == '\t'); e--);
if (s == e)
return (-1);
len = e - s + 1;
if ((buffer = am(myself, len + 1)) == 0)
return (-2);
(void) memcpy(buffer, addr + s, len);
if (inet_pton(AF_INET6, buffer, &addr_ipv6) == 1) {
sfree(buffer);
if (IN6_IS_ADDR_V4COMPAT(&addr_ipv6))
return (0);
if (IN6_IS_ADDR_V4MAPPED(&addr_ipv6))
return (0);
if (newaddr == 0)
return (AF_INET6);
if ((*newaddr = am(myself, INET6_ADDRSTRLEN)) == 0)
return (-2);
if (inet_ntop(AF_INET6, &addr_ipv6, *newaddr, INET6_ADDRSTRLEN))
return (AF_INET6);
sfree(*newaddr);
return (-2);
}
if (inet_pton(AF_INET, buffer, &addr_ipv4) == 1) {
sfree(buffer);
if (newaddr == 0)
return (AF_INET);
if ((*newaddr = am(myself, INET_ADDRSTRLEN)) == 0)
return (-2);
if (inet_ntop(AF_INET, &addr_ipv4, *newaddr, INET_ADDRSTRLEN))
return (AF_INET);
sfree(*newaddr);
return (-2);
}
sfree(buffer);
return (-1);
}
int
sstrncmp(const char *s1, const char *s2, int n) {
if (s1 == 0 && s2 == 0)
return (0);
if (s1 == 0)
return (1);
if (s2 == 0)
return (-1);
return (strncmp(s1, s2, n));
}
char *
trimWhiteSpaces(char *str, int *len, int deallocate) {
char *ostr;
int olen = 0;
int first = 1, i;
char *myself = "trimWhiteSpaces";
if ((ostr = am(myself, *len + 1)) == 0) {
if (deallocate)
sfree(str);
*len = 0;
return (0);
}
for (i = 0; i < *len && (str[i] == ' ' || str[i] == '\t'); i++);
for (; i < *len; i++) {
if (str[i] == ' ' || str[i] == '\t') {
if (first) {
first = 0;
ostr[olen++] = ' ';
}
continue;
}
first = 1;
ostr[olen++] = str[i];
}
if (olen && ostr[olen - 1] == ' ') {
olen--;
ostr[olen] = 0;
}
if (deallocate)
sfree(str);
*len = olen;
return (ostr);
}
int
escapeSpecialChars(__nis_value_t *val) {
int i, j, k, count;
char *newval, *s;
char *myself = "escapeSpecialChars";
for (i = 0; i < val->numVals; i++) {
s = val->val[i].value;
for (j = 0, count = 0; j < val->val[i].length; j++, s++) {
if (*s == '#' || *s == ',' || *s == '+' || *s == '"' ||
*s == '\\' || *s == '<' || *s == '>' || *s == ';')
count++;
}
if (count == 0)
continue;
if ((newval = am(myself, val->val[i].length + count + 1)) == 0)
return (-1);
s = val->val[i].value;
for (j = 0, k = 0; j < val->val[i].length; j++, k++, s++) {
if (*s == '#' || *s == ',' || *s == '+' || *s == '"' ||
*s == '\\' || *s == '<' || *s == '>' || *s == ';')
newval[k++] = '\\';
newval[k] = *s;
}
sfree(val->val[i].value);
val->val[i].value = newval;
val->val[i].length += count;
}
return (1);
}
void
removeEscapeChars(__nis_value_t *val) {
int i;
char *s, *d, *end;
for (i = 0; i < val->numVals; i++) {
s = val->val[i].value;
end = s + val->val[i].length;
for (d = s; s < end; s++, d++) {
if (*s == '\\')
break;
}
for (; s < end; s++) {
if (*s == '\\') {
val->val[i].length--;
s++;
if (s >= end)
break;
}
*d = *s;
d++;
}
}
}