/*
* LIB/SUBS.C
*
* (c)Copyright 1998, Matthew Dillon, All Rights Reserved. Refer to
* the COPYRIGHT file in the base directory of this distribution
* for specific rights granted.
*
*/
#include "defs.h"
Prototype const char *PatExpand(const char *pat);
Prototype void diablo_strlcpy(char *d, const char *s, int ssize, int dsize);
Prototype void diablo_strlcpynl(char *d, const char *s, int ssize, int dsize);
Prototype const char *PatExpand(const char *pat);
Prototype const char *PatLibExpand(const char *pat);
Prototype const char *PatDbExpand(const char *pat);
Prototype const char *PatLogExpand(const char *pat);
Prototype const char *PatSpoolExpand(const char *pat);
Prototype const char *PatRunExpand(const char *pat);
Prototype int CidrMatch(const char *cidr, const char *ip);
Prototype int IsIpAddr(char *a);
Prototype char *SanitiseAddr(char *addr);
Prototype void GetIPHost(struct sockaddr *sa, char *hname, int hnamelen, char *ipname, int iplen);
Prototype int TestForwardLookup(const char *hostName, const char *ipst, const struct sockaddr *res);
Prototype char *NetAddrToSt(int fd, struct sockaddr *sa, int ip4conv, int port, int v6spec);
Prototype int ValidGroupName(const char *name);
Prototype void SanitizeString(char *name);
Prototype void SanitizeDescString(char *name);
Prototype char *StrnCpyNull(char *dst, const char *src, size_t maxlen);
Prototype const char *ftos(double d);
Prototype long bsizetol(char *p);
Prototype double bsizektod(char *p);
Prototype long btimetol(char *p);
Prototype char *dtlenstr(time_t t);
Prototype int MakeGroupDirectory(char *path);
Prototype char *strdupfree(char **st, char *val, char *empty);
Prototype char *safestr(char *st, char *noval);
Prototype int enabled(char *st);
Prototype int HashFeedMatch(HashFeed *hashfeed, int article);
Prototype int MoveFile(char *from, char *to);
Prototype int TimeSpec(char *t, char *def);
u_long ascToAddr(const char *str);
u_long ascToMask(const char *str);
void
diablo_strlcpy(char *d, const char *s, int ssize, int dsize)
{
while (ssize && dsize > 1 && *s) {
*d = *s;
--ssize;
--dsize;
++s;
++d;
}
*d = 0;
}
void
diablo_strlcpynl(char *d, const char *s, int ssize, int dsize)
{
char *dold = d;
while (ssize && *s == ' ') {
++s;
--ssize;
}
while (ssize && dsize > 1 && *s) {
*d = *s;
--ssize;
--dsize;
++s;
++d;
}
*d = 0;
/*
* remove newlines and trailing tabs and spaces
*/
while (d != dold && (d[-1] == '\n' || d[-1] == '\r')) {
--d;
*d = 0;
}
while (d != dold && (d[-1] == '\t' || d[-1] == ' ')) {
--d;
*d = 0;
}
}
static char PatPath1[128];
static char PatPath2[128];
const char *
PatExpand(const char *pat)
{
snprintf(PatPath1, sizeof(PatPath1), pat, NewsHome);
return(PatPath1);
}
const char *
PatLibExpand(const char *pat)
{
snprintf(PatPath2, sizeof(PatPath2), pat, PatExpand(LibHomePat));
return(PatPath2);
}
const char *
PatDbExpand(const char *pat)
{
snprintf(PatPath2, sizeof(PatPath2), pat, PatExpand(DbHomePat));
return(PatPath2);
}
const char *
PatLogExpand(const char *pat)
{
snprintf(PatPath2, sizeof(PatPath2), pat, PatExpand(LogHomePat));
return(PatPath2);
}
const char *
PatSpoolExpand(const char *pat)
{
snprintf(PatPath2, sizeof(PatPath2), pat, PatExpand(SpoolHomePat));
return(PatPath2);
}
const char *
PatRunExpand(const char *pat)
{
snprintf(PatPath2, sizeof(PatPath2), pat, PatExpand(RunHomePat));
return(PatPath2);
}
int
IsIpAddr(char *a)
{
const char *spanstr;
#ifdef INET6
if (strchr(a, ':') != NULL)
spanstr = "0123456789abcdefgh.:/*?[]";
else
#endif
spanstr = "0123456789./*?";
if (strspn(a, spanstr) == strlen(a))
return(1);
else
return(0);
}
/*
* Sanitise an IP[v6] address by removing the '[]'
*/
char *
SanitiseAddr(char *addr)
{
static char st[64];
char *p;
int len;
if (addr == NULL)
return(NULL);
if (*addr == '[')
addr++;
len = strlen(addr);
if ((p = strchr(addr, ']')) != NULL)
len = p - addr;
if (len >= sizeof(st))
len = sizeof(st) - 1;
strncpy(st, addr, len);
st[len] = '\0';
return(st);
}
u_long
ascToAddr(const char *str)
{
char string[32];
char *ptr;
u_long i, a, b, c, d;
snprintf(string, sizeof(string), "%s", str);
if ((ptr = strchr(string, '/')))
*ptr = '\0';
/* Count the dots. */
ptr = string;
i = 0;
while (*ptr)
if (*ptr++ == '.')
i++;
if (i == 0) {
sscanf(string, "%ld", &a);
return(a << 24);
} else if (i == 1) {
sscanf(string, "%ld.%ld", &a, &b);
return((a << 24) + (b << 16));
} else if (i == 2) {
sscanf(string, "%ld.%ld.%ld", &a, &b, &c);
return((a << 24) + (b << 16) + (c << 8));
} else {
sscanf(string, "%ld.%ld.%ld.%ld", &a, &b, &c, &d);
return((a << 24) + (b << 16) + (c << 8) + d);
}
}
u_long
ascToMask(const char *str)
{
char *ptr;
u_long i;
if ((ptr = strchr(str, '/')))
ptr++;
else
return(0xffffffff);
/* Accept either CIDR /nn or /xxx.xxx.xxx.xxx */
if (strstr(ptr, ".")) {
return(ntohl(inet_addr(ptr)));
} else {
i = atoi(ptr);
if (!i)
return(0);
else
return((u_long) 0xffffffff << (32 - i));
}
}
/*
* Match CIDR address - return 1 for sucess else 0
*
* This is really messy
*/
int
CidrMatch(const char *cidr, const char *ip)
{
#ifdef INET6
char addr[256];
char mask[256];
uint8 maskbits = 128;
char maskst[NI_MAXHOST];
char *p;
int i;
if (strchr(ip, ':') != NULL) {
uint8 b8;
uint8 b;
if (strchr(cidr, ':') == NULL) /* Don't compare against non v6 CIDR */
return(0);
strcpy(maskst, cidr);
if ((p = strchr(maskst, '/')) != NULL) {
*p = '\0';
maskbits = atoi(++p);
}
if (inet_pton(AF_INET6, ip, addr) != 1) {
logit(LOG_ERR, "Invalid IPv6 address: %s", ip);
return(0);
}
if (inet_pton(AF_INET6, maskst, mask) != 1) {
logit(LOG_ERR, "Invalid IPv6 address: %s", cidr);
return(0);
}
for (i = 0; i * 8 < maskbits; i++) {
if (i < maskbits / 8)
b8 = 255;
else
for (b8 = 0, b = 0; b < maskbits % 8; b++)
b8 |= (1 << (7 - b));
if ((addr[i] & b8) != (mask[i] & b8))
return(0);
}
return(1);
} else
#endif
{
u_long net;
u_long mask;
u_long addr;
if (strchr(cidr, ':') != NULL) /* Don't compare against v6 CIDR */
return(0);
addr = ascToAddr(ip);
net = ascToAddr(cidr);
mask = ascToMask(cidr);
if ((addr & mask) != (net & mask))
return(0);
return(1);
}
}
void
GetIPHost(struct sockaddr *sa, char *hname, int hnamelen, char *ipname, int iplen)
{
strncpy(ipname, NetAddrToSt(0, sa, 1, 0, 0), iplen - 1);
ipname[iplen - 1] = '\0';
*hname = '\0';
{
#ifdef INET6
int error;
if ((error = getnameinfo(sa, SA_LEN(sa), hname, hnamelen,
NULL, 0, NI_NAMEREQD)) != 0)
*hname = '\0';
#else
struct hostent *he;
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
he = gethostbyaddr(
(char *)&sin->sin_addr,
sizeof(sin->sin_addr),
AF_INET
);
if (he != NULL) {
strncpy(hname, he->h_name, hnamelen - 1);
hname[hnamelen - 1] = '\0';
}
#endif /* INET6 */
}
}
/*
* TestForwardLookup().
*
* Check that Fwd and Rev DNS entries match up
*/
int
TestForwardLookup(const char *hostName, const char *ipst, const struct sockaddr *sa)
{
#ifdef INET6
struct addrinfo *ai0;
int r = -1;
stprintf("forward auth %s", hostName);
if (getaddrinfo(hostName, NULL, NULL, &ai0) == 0) {
struct addrinfo *ai;
for (ai = ai0; ai; ai = ai->ai_next) {
char *st = NetAddrToSt(0, ai->ai_addr, 1, 0, 0);
if (st != NULL && strcmp(ipst, st) == 0) {
r = 0;
break;
}
}
if (ai == NULL)
logit(LOG_NOTICE, "DNS Fwd/Rev mismatch: %s/%s", hostName, ipst);
freeaddrinfo(ai0);
} else {
logit(LOG_NOTICE, "DNS Fwd/Rev mismatch: lookup of %s failed", hostName);
}
return(r);
#else
struct hostent *he;
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
int r = -1;
if ((he = gethostbyname(hostName)) != NULL) {
int i;
for (i = 0; he->h_addr_list && he->h_addr_list[i]; ++i) {
const struct in_addr *haddr = (const void *)he->h_addr_list[i];
if (sin->sin_addr.s_addr == haddr->s_addr) {
r = 0;
break;
}
}
if (he->h_addr_list[i] == NULL)
logit(LOG_NOTICE, "DNS Fwd/Rev mismatch: %s/%s", hostName, ipst);
} else {
logit(LOG_NOTICE, "DNS Fwd/Rev mismatch: lookup of %s failed", hostName);
}
return(r);
#endif
}
int
ValidGroupName(const char *name)
{
int r = 0;
if (name[0] == 0 || name[0] == '.') {
r = -1;
} else {
for (; *name; ++name) {
if (*name == ' ' || ! isprint((int)*name)) {
r = -1;
}
if (*name >= 'a' && *name <= 'z')
continue;
if (*name >= 'A' && *name <= 'Z')
continue;
if (*name >= '0' && *name <= '9')
continue;
if (*name == '+')
continue;
if (*name == '-')
continue;
if (*name == '.') {
if (name[-1] == '.' || name[1] == '.' || name[1] == 0)
r = -1;
}
}
}
return(r);
}
void
SanitizeString(char *name)
{
for (; *name; ++name) {
if (*name >= 'a' && *name <= 'z')
continue;
if (*name >= 'A' && *name <= 'Z')
continue;
if (*name >= '0' && *name <= '9')
continue;
if (*name == '\t')
*name = ' ';
if (*name == '@' ||
*name == '-' ||
*name == '+' ||
*name == '_' ||
*name == '.' ||
*name == ',' ||
*name == ' '
) {
continue;
}
*name = '?';
}
}
/*
* Sanitise a group description
*/
void
SanitizeDescString(char *name)
{
for (; *name; ++name) {
if (*name == '\t')
*name = ' ';
if (!iscntrl((int)*name))
continue;
*name = '?';
}
}
/*
* StrnCpyNull()
*
* Like strcpy, but gracefully handles null pointers and limits the length
* of the string copied.
*/
char *
StrnCpyNull(char *dst, const char *src, size_t maxlen)
{
if (dst) {
if (src) {
if (strlen(src) >= maxlen) {
strncpy(dst, src, maxlen - 1);
dst[maxlen - 1] = '\0';
}
else {
strcpy(dst, src);
}
}
else {
*dst = '\0';
}
}
return dst;
}
#define ONE_K 1024.0
#define ONE_M (1024.0*1024.0)
#define ONE_G (1024.0*1024.0*1024.0)
#define ONE_T (1024.0*1024.0*1024.0*1024.0)
const char *
ftos(double d)
{
static char FBuf[8][32];
static int FCnt;
char *p = FBuf[FCnt];
if (d < 1024.0) {
sprintf(p, "%d", (int)d);
} else if (d < ONE_M) {
sprintf(p, "%d.%03dK", (int)(d / ONE_K), ((int)d % (int)ONE_K) * 1000 / (int)ONE_K);
} else if (d < ONE_G) {
sprintf(p, "%d.%03dM", (int)(d / ONE_M), ((int)(d / ONE_K) % (int)ONE_K) * 1000 / (int)ONE_K);
} else if (d < ONE_T) {
sprintf(p, "%d.%03dG", (int)(d / ONE_G), ((int)(d / ONE_M) % (int)ONE_K) * 1000 / (int)ONE_K);
} else {
sprintf(p, "%d.%03dT", (int)(d / ONE_T), ((int)(d / ONE_G) % (int)(d / ONE_M) % (int)ONE_K) * 1000 / (int)ONE_K);
}
FCnt = (FCnt + 1) & 7;
return(p);
}
/*
* Convert a string value to a number of bytes. The string can be
* specified in kb, mb or gb
*/
long
bsizetol(char *p)
{
long n;
n = strtol(p, &p, 0);
switch(*p) {
case 'g':
case 'G':
n *= 1024;
/* fall through */
case 'm':
case 'M':
n *= 1024;
/* fall through */
case 'k':
case 'K':
n *= 1024;
break;
}
return(n);
}
/*
* Convert a string value to a number of kilobytes
*/
double
bsizektod(char *p)
{
double n;
n = strtol(p, &p, 0) * 1024.0;
switch(*p) {
case 'g':
case 'G':
n *= 1024.0;
/* fall through */
case 'm':
case 'M':
n *= 1024.0;
break;
/* fall through */
case 't':
case 'T':
n *= 1024.0;
break;
}
return(n);
}
/*
* Convert a time specification in days, hours, mins and/or secs to a long
* representing the number of secs. The specification can include
* multiple time specifications.
*/
long
btimetol(char *p)
{
long n;
long res = 0;
while (*p) {
while (*p && !(int)isdigit(*p))
p++;
n = strtol(p, &p, 0);
while (*p && (int)isdigit(*p))
p++;
switch(*p) {
case 'd':
case 'D':
n *= 24;
/* fall through */
case 'h':
case 'H':
n *= 60;
/* fall through */
case 'm':
case 'M':
n *= 60;
break;
case 's':
case 'S':
case ' ':
break;
default:
p++;
}
p++;
res += n;
}
return(res);
}
char *
dtlenstr(time_t t)
{
int d = 0;
int h = 0;
int m = 0;
static char tb[64];
if (t > 24 * 60 * 60) {
d = t / (24 * 60 * 60);
t = t % (24 * 60 * 60);
}
if (t > 60 * 60) {
h = t / (60 * 60);
t = t % (60 * 60);
}
if (t > 60) {
m = t / 60;
t = t % 60;
}
sprintf(tb, "%d days %d hrs %d min %d sec", d, h, m, (int)t);
return(tb);
}
#ifdef INET6
/*
* A protocol independent conversion of network address to string
*
* Strips the initial portion of a IPv6 encoded IPv4 address if
* requested
*
* If sa == NULL then the address is obtained from the fd passed
* otherwise the fd is ignored.
*/
char *
NetAddrToSt(int fd, struct sockaddr *sa, int ip4conv, int port, int v6spec)
{
static char st[NI_MAXHOST + 8];
char addrst[NI_MAXHOST];
char serv[16];
int error;
if (sa == NULL) {
static struct sockaddr_storage res;
int salen = sizeof(res);
sa = (struct sockaddr *)&res;
if (getpeername(fd, sa, &salen) != 0) {
logit(LOG_ERR, "%s", strerror(errno));
return(NULL);
}
}
if (SA_LEN(sa) == 0)
return(NULL);
if ((error = getnameinfo(sa, SA_LEN(sa), addrst, sizeof(addrst),
serv, sizeof(serv),
NI_NUMERICHOST|NI_NUMERICSERV)) == 0) {
if (v6spec && strchr(addrst, ':')) {
snprintf(st, sizeof(st), "[%s]", addrst);
} else {
strncpy(st, addrst, sizeof(st) - 1);
st[sizeof(st) - 1] = '\0';
}
if (port) {
strncat(st, ":", sizeof(st) - 1);
strncat(st, serv, sizeof(st) - 1);
}
if (ip4conv && strncmp(st, "::ffff:", 7) == 0)
return(st + 7);
else
return(st);
} else {
logit(LOG_ERR, "getnameinfo: %s\n", gai_strerror(error));
}
return(NULL);
}
#else
char *
NetAddrToSt(int fd, struct sockaddr *sa, int ip4conv, int port, int v6spec)
{
static char st[128];
struct sockaddr_in *sin = (struct sockaddr_in *)sa;
strncpy(st, inet_ntoa(sin->sin_addr), sizeof(st) - 1);
st[sizeof(st) - 1] = '\0';
if (port) {
char port[16];
snprintf(port, sizeof(port), ":%d", ntohs(sin->sin_port));
strncat(st, port, sizeof(st) - 1);
}
return(st);
}
#endif
/*
* Create the directories required for the file pathname specified in path
* path = the full path/filename which gets clobbered.
*/
int
MakeGroupDirectory(char *path)
{
char dir[PATH_MAX];
char *p;
struct stat st;
strcpy(dir, path);
if (strchr(dir, '/') == NULL)
return(0);
if ((p = strrchr(dir, '/')) != NULL)
*p = '\0';
if (stat(dir, &st) == 0)
return(0);
if (MakeGroupDirectory(dir) == -1)
return(-1);
return(mkdir(dir, 0755));
}
/*
* If the string exists, free it
* strdup the value
* if value is "0", then set string to NULL
*/
char *
strdupfree(char **st, char *val, char *empty)
{
if (*st != NULL)
free(*st);
if (val == NULL || strcmp(val, "0") == 0)
*st = (empty == NULL) ? NULL : strdup(empty);
else
*st = strdup(val);
return(*st);
}
/*
* Return a string that isn't NULL
*/
char *
safestr(char *st, char *noval)
{
if (st == NULL)
return((noval != NULL) ? noval : "NONE");
return(st);
}
int
enabled(char *st)
{
if (st == NULL || !*st || *st == 'y' || *st == 'Y' ||
strcasecmp(st, "on") == 0 || *st == '1')
return(1);
else
return(0);
}
int
HashFeedMatch(HashFeed *hashfeed, int hash)
{
if (DebugOpt > 1)
printf("hash=%d mod=%d begin=%d end=%d res=%d match=%d\n", hash,
hashfeed->hf_Mod,
hashfeed->hf_Begin,
hashfeed->hf_End,
hash % hashfeed->hf_Mod + 1,
((hash % hashfeed->hf_Mod + 1) >= hashfeed->hf_Begin &&
(hash % hashfeed->hf_Mod + 1) <= hashfeed->hf_End)
);
return ((hash % hashfeed->hf_Mod + 1) >= hashfeed->hf_Begin &&
(hash % hashfeed->hf_Mod + 1) <= hashfeed->hf_End);
}
int
MoveFile(char *from, char *to)
{
int from_fd;
int to_fd;
static char buffer[32768];
int rlen;
if ((from_fd = open(from, O_RDONLY, 0)) < 0) {
printf("ERROR: Unable to open input file: %s\n", from);
return(-1);
}
if ((to_fd = open(to, O_CREAT | O_TRUNC | O_WRONLY, 0644)) < 0) {
printf("ERROR: Unable to create output file: %s\n", to);
return(-1);
}
while ((rlen = read(from_fd, buffer, 32768)) > 0)
if (write(to_fd, buffer, rlen) != rlen) {
printf("ERROR: Unable to writing to file: %s\n", to);
close(from_fd);
close(to_fd);
unlink(to);
return(-1);
}
if (rlen < 0) {
printf("ERROR: Unable to read from file: %s\n", from);
close(from_fd);
close(to_fd);
unlink(to);
return(-1);
}
close(from_fd);
if (close(to_fd) != 0) {
printf("ERROR: Unable to close file: %s\n", to);
unlink(to);
return(-1);
}
unlink(from);
return(0);
}
/*
* Convert a string time specification in days, hours, minutes or seconds
* into a integer of seconds.
*/
int
TimeSpec(char *t, char *def)
{
char *endp;
int tt;
tt = strtol(t, &endp, 0);
if (endp == NULL || !*endp)
endp = def;
switch (*endp) {
case 's':
break;
case 'm':
tt *= 60;
break;
case 'h':
tt *= 60 * 60;
break;
case 'd':
tt *= 24 * 60 * 60;
break;
default:
fprintf(stderr, "Invalid time specification: %s \n", t);
tt = -1;
}
return(tt);
}
syntax highlighted by Code2HTML, v. 0.9.1