1
0
mirror of https://github.com/anope/anope.git synced 2026-06-25 08:56:39 +02:00
Files
anope/src/misc.c
T

1617 lines
36 KiB
C

/* Miscellaneous routines.
*
* (C) 2003-2009 Anope Team
* Contact us at team@anope.org
*
* Please read COPYING and README for further details.
*
* Based on the original code of Epona by Lara.
* Based on the original code of Services by Andy Church.
*
* $Id$
*
*/
#include "services.h"
#include "language.h"
#include "hashcomp.h" // If this gets added to services.h or someplace else later, remove it from here -- CyberBotX
/* Cheaper than isspace() or isblank() */
#define issp(c) ((c) == 32)
struct arc4_stream {
uint8 i;
uint8 j;
uint8 s[256];
} rs;
/*************************************************************************/
/**
* toupper: Like the ANSI functions, but make sure we return an
* int instead of a (signed) char.
* @param c Char
* @return int
*/
int toupper(char c)
{
if (islower(c)) {
return static_cast<int>(c) - ('a' - 'A');
} else {
return static_cast<int>(c);
}
}
/*************************************************************************/
/**
* tolower: Like the ANSI functions, but make sure we return an
* int instead of a (signed) char.
* @param c Char
* @return int
*/
int tolower(char c)
{
if (isupper(c)) {
return static_cast<int>(c) + ('a' - 'A');
} else {
return static_cast<int>(c);
}
}
/*************************************************************************/
/**
* Simple function to convert binary data to hex.
* Taken from hybrid-ircd ( http://ircd-hybrid.com/ )
*/
void binary_to_hex(unsigned char *bin, char *hex, int length)
{
static const char trans[] = "0123456789ABCDEF";
int i;
for (i = 0; i < length; i++) {
hex[i << 1] = trans[bin[i] >> 4];
hex[(i << 1) + 1] = trans[bin[i] & 0xf];
}
hex[i << 1] = '\0';
}
/*************************************************************************/
/**
* strscpy: Copy at most len-1 characters from a string to a buffer, and
* add a null terminator after the last character copied.
* @param d Buffer to copy into
* @param s Data to copy int
* @param len Length of data
* @return updated buffer
*/
char *strscpy(char *d, const char *s, size_t len)
{
char *d_orig = d;
if (!len) {
return d;
}
while (--len && (*d++ = *s++));
*d = '\0';
return d_orig;
}
/*************************************************************************/
/**
* stristr: Search case-insensitively for string s2 within string s1,
* returning the first occurrence of s2 or NULL if s2 was not
* found.
* @param s1 String 1
* @param s2 String 2
* @return first occurrence of s2
*/
char *stristr(char *s1, char *s2)
{
register char *s = s1, *d = s2;
while (*s1) {
if (tolower(*s1) == tolower(*d)) {
s1++;
d++;
if (*d == 0)
return s;
} else {
s = ++s1;
d = s2;
}
}
return NULL;
}
/*************************************************************************/
/**
* strnrepl: Replace occurrences of `old' with `new' in string `s'. Stop
* replacing if a replacement would cause the string to exceed
* `size' bytes (including the null terminator). Return the
* string.
* @param s String
* @param size size of s
* @param old character to replace
* @param newstr character to replace with
* @return updated s
*/
char *strnrepl(char *s, int32 size, const char *old, const char *newstr)
{
char *ptr = s;
int32 left = strlen(s);
int32 avail = size - (left + 1);
int32 oldlen = strlen(old);
int32 newlen = strlen(newstr);
int32 diff = newlen - oldlen;
while (left >= oldlen) {
if (strncmp(ptr, old, oldlen) != 0) {
left--;
ptr++;
continue;
}
if (diff > avail)
break;
if (diff != 0)
memmove(ptr + oldlen + diff, ptr + oldlen, left + 1 - oldlen);
strncpy(ptr, newstr, newlen);
ptr += newlen;
left -= oldlen;
}
return s;
}
/*************************************************************************/
/**
* merge_args: Take an argument count and argument vector and merge them
* into a single string in which each argument is separated by
* a space.
* @param int Number of Args
* @param argv Array
* @return string of the merged array
*/
const char *merge_args(int argc, const char **argv)
{
int i;
static char s[4096];
char *t;
t = s;
for (i = 0; i < argc; i++)
t += snprintf(t, sizeof(s) - (t - s), "%s%s", *argv++,
(i < argc - 1) ? " " : "");
return s;
}
/*
* XXX: temporary "safe" version to avoid casting, it's still ugly.
*/
const char *merge_args(int argc, char **argv)
{
int i;
static char s[4096];
char *t;
t = s;
for (i = 0; i < argc; i++)
t += snprintf(t, sizeof(s) - (t - s), "%s%s", *argv++,
(i < argc - 1) ? " " : "");
return s;
}
/*************************************************************************/
/**
* do_match_wild: Attempt to match a string to a pattern which might contain
* '*' or '?' wildcards. Return 1 if the string matches the
* pattern, 0 if not.
* @param pattern To be matched
* @param str String in which the pattern is to be matched
* @param docase Case In/Senstive
* @return 1 if the string matches the pattern, 0 if not.
*/
static int do_match_wild(const char *pattern, const char *str, int docase)
{
char c;
const char *s;
if (!str || !*str || !pattern || !*pattern) {
return 0;
}
/* This WILL eventually terminate: either by *pattern == 0, or by a
* trailing '*'. */
for (;;) {
switch (c = *pattern++) {
case 0:
if (!*str)
return 1;
return 0;
case '?':
if (!*str)
return 0;
str++;
break;
case '*':
if (!*pattern)
return 1; /* trailing '*' matches everything else */
s = str;
while (*s) {
if ((docase ? (*s == *pattern)
: (tolower(*s) == tolower(*pattern)))
&& do_match_wild(pattern, s, docase))
return 1;
s++;
}
break;
default:
if (docase ? (*str++ != c) : (tolower(*str++) != tolower(c)))
return 0;
break;
} /* switch */
}
}
/*************************************************************************/
/**
* match_wild: Case Senstive wild card search
* @param pattern To be matched
* @param str String in which the pattern is to be matched
* @return 1 if the string matches the pattern, 0 if not.
*/
int match_wild(const char *pattern, const char *str)
{
return do_match_wild(pattern, str, 1);
}
/*************************************************************************/
/**
* match_wild: Case Insenstive wild card search
* @param pattern To be matched
* @param str String in which the pattern is to be matched
* @return 1 if the string matches the pattern, 0 if not.
*/
int match_wild_nocase(const char *pattern, const char *str)
{
return do_match_wild(pattern, str, 0);
}
/*************************************************************************/
/**
* Process a string containing a number/range list in the form
* "n1[-n2][,n3[-n4]]...", calling a caller-specified routine for each
* number in the list. If the callback returns -1, stop immediately.
* Returns the sum of all nonnegative return values from the callback.
* If `count' is non-NULL, it will be set to the total number of times the
* callback was called.
*
* The callback should be of type range_callback_t, which is defined as:
* int (*range_callback_t)(User *u, int num, va_list args)
* @param numstr
* @param count_ret
* @param callback Call back function
* @param u User Struct
* @param ... various args
* @return int
*/
int process_numlist(const char *numstr, int *count_ret,
range_callback_t callback, User * u, ...)
{
int n1, n2, i;
int res = 0, retval = 0, count = 0;
va_list args, preserve;
if (!numstr || !*numstr) {
return -1;
}
va_start(args, u);
/*
* This algorithm ignores invalid characters, ignores a dash
* when it precedes a comma, and ignores everything from the
* end of a valid number or range to the next comma or null.
*/
for (;;) {
n1 = n2 = strtol(numstr, const_cast<char **>(&numstr), 10);
numstr += strcspn(numstr, "0123456789,-");
if (*numstr == '-') {
numstr++;
numstr += strcspn(numstr, "0123456789,");
if (isdigit(*numstr)) {
n2 = strtol(numstr, const_cast<char **>(&numstr), 10);
numstr += strcspn(numstr, "0123456789,-");
}
}
for (i = n1; i <= n2 && i >= 0; i++) {
VA_COPY(preserve, args);
res = callback(u, i, preserve);
va_end(preserve);
count++;
if (res < 0)
break;
retval += res;
if (count >= 32767) {
if (count_ret)
*count_ret = count;
return retval;
}
}
if (res < -1)
break;
numstr += strcspn(numstr, ",");
if (*numstr)
numstr++;
else
break;
}
if (count_ret)
*count_ret = count;
va_end(args);
return retval;
}
/*************************************************************************/
/**
* dotime: Return the number of seconds corresponding to the given time
* string. If the given string does not represent a valid time,
* return -1.
*
* A time string is either a plain integer (representing a number
* of seconds), or an integer followed by one of these characters:
* "s" (seconds), "m" (minutes), "h" (hours), or "d" (days).
* @param s String to convert
* @return int
*/
int dotime(const char *s)
{
int amount;
if (!s || !*s) {
return -1;
}
amount = strtol(s, const_cast<char **>(&s), 10);
if (*s) {
switch (*s) {
case 's':
return amount;
case 'm':
return amount * 60;
case 'h':
return amount * 3600;
case 'd':
return amount * 86400;
default:
return -1;
}
} else {
return amount;
}
}
/*************************************************************************/
/**
* Expresses in a string the period of time represented by a given amount
* of seconds (with days/hours/minutes).
* @param na Nick Alias
* @param buf buffer to store result into
* @param bufsize Size of the buffer
* @param seconds time in seconds
* @return buffer
*/
char *duration(NickAlias * na, char *buf, int bufsize, time_t seconds)
{
int days = 0, hours = 0, minutes = 0;
int need_comma = 0;
char buf2[64], *end;
const char *comma = getstring(na, COMMA_SPACE);
/* We first calculate everything */
days = seconds / 86400;
seconds -= (days * 86400);
hours = seconds / 3600;
seconds -= (hours * 3600);
minutes = seconds / 60;
if (!days && !hours && !minutes) {
snprintf(buf, bufsize,
getstring(na,
(seconds <=
1 ? DURATION_SECOND : DURATION_SECONDS)),
seconds);
} else {
end = buf;
if (days) {
snprintf(buf2, sizeof(buf2),
getstring(na,
(days == 1 ? DURATION_DAY : DURATION_DAYS)),
days);
end += snprintf(end, bufsize - (end - buf), "%s", buf2);
need_comma = 1;
}
if (hours) {
snprintf(buf2, sizeof(buf2),
getstring(na,
(hours ==
1 ? DURATION_HOUR : DURATION_HOURS)),
hours);
end +=
snprintf(end, bufsize - (end - buf), "%s%s",
(need_comma ? comma : ""), buf2);
need_comma = 1;
}
if (minutes) {
snprintf(buf2, sizeof(buf2),
getstring(na,
(minutes ==
1 ? DURATION_MINUTE : DURATION_MINUTES)),
minutes);
end +=
snprintf(end, bufsize - (end - buf), "%s%s",
(need_comma ? comma : ""), buf2);
need_comma = 1;
}
}
return buf;
}
/*************************************************************************/
/**
* Generates a human readable string of type "expires in ..."
* @param na Nick Alias
* @param buf buffer to store result into
* @param bufsize Size of the buffer
* @param seconds time in seconds
* @return buffer
*/
char *expire_left(NickAlias * na, char *buf, int len, time_t expires)
{
time_t now = time(NULL);
if (!expires) {
strncpy(buf, getstring(na, NO_EXPIRE), len);
} else if (expires <= now) {
strncpy(buf, getstring(na, EXPIRES_SOON), len);
} else {
time_t diff = expires - now + 59;
if (diff >= 86400) {
int days = diff / 86400;
snprintf(buf, len,
getstring(na, (days == 1) ? EXPIRES_1D : EXPIRES_D),
days);
} else {
if (diff <= 3600) {
int minutes = diff / 60;
snprintf(buf, len,
getstring(na,
(minutes ==
1) ? EXPIRES_1M : EXPIRES_M), minutes);
} else {
int hours = diff / 3600, minutes;
diff -= (hours * 3600);
minutes = diff / 60;
snprintf(buf, len,
getstring(na,
((hours == 1
&& minutes ==
1) ? EXPIRES_1H1M : ((hours == 1
&& minutes !=
1) ? EXPIRES_1HM
: ((hours != 1
&& minutes ==
1) ?
EXPIRES_H1M :
EXPIRES_HM)))),
hours, minutes);
}
}
}
return buf;
}
/*************************************************************************/
/**
* Validate the host
* shortname = ( letter / digit ) *( letter / digit / "-" ) *( letter / digit )
* hostname = shortname *( "." shortname )
* ip4addr = 1*3digit "." 1*3digit "." 1*3digit "." 1*3digit
* @param host = string to check
* @param type = format, 1 = ip4addr, 2 = hostname
* @return 1 if a host is valid, 0 if it isnt.
*/
int doValidHost(const char *host, int type)
{
int idx = 0;
int len = 0;
int sec_len = 0;
int dots = 1;
if (type != 1 && type != 2) {
return 0;
}
if (!host) {
return 0;
}
len = strlen(host);
if (len > HOSTMAX) {
return 0;
}
switch (type) {
case 1:
for (idx = 0; idx < len; idx++) {
if (isdigit(host[idx])) {
if (sec_len < 3) {
sec_len++;
} else {
return 0;
}
} else {
if (idx == 0) {
return 0;
} /* cant start with a non-digit */
if (host[idx] != '.') {
return 0;
} /* only . is a valid non-digit */
if (sec_len > 3) {
return 0;
} /* sections cant be more than 3 digits */
sec_len = 0;
dots++;
}
}
if (dots != 4) {
return 0;
}
break;
case 2:
dots = 0;
for (idx = 0; idx < len; idx++) {
if (!isalnum(host[idx])) {
if (idx == 0) {
return 0;
}
if ((host[idx] != '.') && (host[idx] != '-')) {
return 0;
}
if (host[idx] == '.') {
dots++;
}
}
}
if (host[len - 1] == '.') {
return 0;
}
/**
* Ultimate3 dosnt like a non-dotted hosts at all, nor does unreal,
* so just dont allow them.
**/
if (dots == 0) {
return 0;
}
break;
}
return 1;
}
/*************************************************************************/
/**
* Front end to doValidHost
* @param host = string to check
* @param type = format, 1 = ip4addr, 2 = hostname
* @return 1 if a host is valid, 0 if it isnt.
*/
int isValidHost(const char *host, int type)
{
int status = 0;
if (type == 3) {
if (!(status = doValidHost(host, 1))) {
status = doValidHost(host, 2);
}
} else {
status = doValidHost(host, type);
}
return status;
}
/*************************************************************************/
/**
* Valid character check
* @param c Character to check
* @return 1 if a host is valid, 0 if it isnt.
*/
int isvalidchar(const char c)
{
if (((c >= 'A') && (c <= 'Z')) ||
((c >= 'a') && (c <= 'z')) ||
((c >= '0') && (c <= '9')) || (c == '.') || (c == '-'))
return 1;
else
return 0;
}
/*************************************************************************/
/**
* Get the token
* @param str String to search in
* @param dilim Character to search for
* @param token_number the token number
* @return token
*/
char *myStrGetToken(const char *str, const char dilim, int token_number)
{
int len, idx, counter = 0, start_pos = 0;
char *substring = NULL;
if (!str) {
return NULL;
}
len = strlen(str);
for (idx = 0; idx <= len; idx++) {
if ((str[idx] == dilim) || (idx == len)) {
if (counter == token_number) {
substring = myStrSubString(str, start_pos, idx);
counter++;
} else {
start_pos = idx + 1;
counter++;
}
}
}
return substring;
}
/*************************************************************************/
/**
* Get the token only
* @param str String to search in
* @param dilim Character to search for
* @param token_number the token number
* @return token
*/
char *myStrGetOnlyToken(const char *str, const char dilim,
int token_number)
{
int len, idx, counter = 0, start_pos = 0;
char *substring = NULL;
if (!str) {
return NULL;
}
len = strlen(str);
for (idx = 0; idx <= len; idx++) {
if (str[idx] == dilim) {
if (counter == token_number) {
if (str[idx] == '\r')
substring = myStrSubString(str, start_pos, idx - 1);
else
substring = myStrSubString(str, start_pos, idx);
counter++;
} else {
start_pos = idx + 1;
counter++;
}
}
}
return substring;
}
/*************************************************************************/
/**
* Get the Remaining tokens
* @param str String to search in
* @param dilim Character to search for
* @param token_number the token number
* @return token
*/
char *myStrGetTokenRemainder(const char *str, const char dilim,
int token_number)
{
int len, idx, counter = 0, start_pos = 0;
char *substring = NULL;
if (!str) {
return NULL;
}
len = strlen(str);
for (idx = 0; idx <= len; idx++) {
if ((str[idx] == dilim) || (idx == len)) {
if (counter == token_number) {
substring = myStrSubString(str, start_pos, len);
counter++;
} else {
start_pos = idx + 1;
counter++;
}
}
}
return substring;
}
/*************************************************************************/
/**
* Get the string between point A and point B
* @param str String to search in
* @param start Point A
* @param end Point B
* @return the string in between
*/
char *myStrSubString(const char *src, int start, int end)
{
char *substring = NULL;
int len, idx;
if (!src) {
return NULL;
}
len = strlen(src);
if (((start >= 0) && (end <= len)) && (end > start)) {
substring = new char[(end - start) + 1];
for (idx = 0; idx <= end - start; idx++) {
substring[idx] = src[start + idx];
}
substring[end - start] = '\0';
}
return substring;
}
/*************************************************************************/
/**
* Clean up the buffer for extra spaces
* @param str to clean up
* @return void
*/
void doCleanBuffer(char *str)
{
char *in, *out;
char ch;
if (!str) {
return;
}
in = str;
out = str;
while (issp(ch = *in++));
if (ch != '\0')
for (;;) {
*out++ = ch;
ch = *in++;
if (ch == '\0')
break;
if (!issp(ch))
continue;
while (issp(ch = *in++));
if (ch == '\0')
break;
*out++ = ' ';
}
*out = ch; /* == '\0' */
}
/*************************************************************************/
/**
* Kill the user to enforce the sqline
* @param nick to kill
* @param killer whom is doing the killing
* @return void
*/
void EnforceQlinedNick(const char *nick, const char *killer)
{
User *u2;
if ((u2 = finduser(nick))) {
alog("Killed Q-lined nick: %s!%s@%s", u2->nick, u2->GetIdent().c_str(),
u2->host);
kill_user(killer, u2->nick,
"This nick is reserved for Services. Please use a non Q-Lined nick.");
}
}
/*************************************************************************/
/**
* Is the given nick a network service
* @param nick to check
* @param int Check if botserv bots
* @return int
*/
int nickIsServices(const char *tempnick, int bot)
{
int found = 0;
char *s, *nick;
if (!tempnick) {
return found;
}
nick = sstrdup(tempnick);
s = strchr(nick, '@');
if (s) {
*s++ = 0;
if (stricmp(s, ServerName) != 0) {
delete [] nick;
return found;
}
}
if (s_NickServ && (stricmp(nick, s_NickServ) == 0))
found++;
else if (s_ChanServ && (stricmp(nick, s_ChanServ) == 0))
found++;
else if (s_HostServ && (stricmp(nick, s_HostServ) == 0))
found++;
else if (s_MemoServ && (stricmp(nick, s_MemoServ) == 0))
found++;
else if (s_BotServ && (stricmp(nick, s_BotServ) == 0))
found++;
else if (s_HelpServ && (stricmp(nick, s_HelpServ) == 0))
found++;
else if (s_OperServ && (stricmp(nick, s_OperServ) == 0))
found++;
else if (s_GlobalNoticer && (stricmp(nick, s_GlobalNoticer) == 0))
found++;
else if (s_BotServ && bot) {
BotInfo *bi;
int i;
for (i = 0; i < 256; i++) {
for (bi = botlists[i]; bi; bi = bi->next) {
if (stricmp(nick, bi->nick) == 0) {
found++;
continue;
}
}
}
}
/* Somehow, something tells me we should free this :) -GD */
delete [] nick;
return found;
}
/*************************************************************************/
/**
* arc4 init
* @return void
*/
static void arc4_init()
{
int n;
for (n = 0; n < 256; n++)
rs.s[n] = n;
rs.i = 0;
rs.j = 0;
}
/*************************************************************************/
/**
* arc4 addrandom
* @param data
* @param dalen Data Length
* @return void
*/
static void arc4_addrandom(void *dat, int datlen)
{
int n;
uint8 si;
rs.i--;
for (n = 0; n < 256; n++) {
rs.i = (rs.i + 1);
si = rs.s[rs.i];
rs.j = (rs.j + si + (static_cast<unsigned char *>(dat))[n % datlen]);
rs.s[rs.i] = rs.s[rs.j];
rs.s[rs.j] = si;
}
}
/*************************************************************************/
/**
* random init
* @return void
*/
void rand_init()
{
#ifndef _WIN32
int n, fd;
#endif
struct {
#ifdef USE_MYSQL
int sqlrand;
#endif
#ifndef _WIN32
struct timeval nowt; /* time */
char rnd[32]; /* /dev/urandom */
#else
MEMORYSTATUS mstat; /* memory status */
struct _timeb nowt; /* time */
#endif
} rdat;
arc4_init();
/* Grab "random" MYSQL data */
#ifdef USE_MYSQL
rdat.sqlrand = mysql_rand();
#endif
/* Grab OS specific "random" data */
#ifndef _WIN32
/* unix/bsd: time */
gettimeofday(&rdat.nowt, NULL);
/* unix/bsd: /dev/urandom */
fd = open("/dev/urandom", O_RDONLY);
if (fd) {
n = read(fd, &rdat.rnd, sizeof(rdat.rnd));
close(fd);
}
#else
/* win32: time */
_ftime(&rdat.nowt);
/* win32: memory status */
GlobalMemoryStatus(&rdat.mstat);
#endif
arc4_addrandom(&rdat, sizeof(rdat));
}
/*************************************************************************/
/**
* Setup the random numbers
* @return void
*/
void add_entropy_userkeys()
{
arc4_addrandom(&UserKey1, sizeof(UserKey1));
arc4_addrandom(&UserKey2, sizeof(UserKey2));
arc4_addrandom(&UserKey3, sizeof(UserKey3));
/* UserKey3 is also used in mysql_rand() */
}
/*************************************************************************/
/**
* Get the random numbers 8 byte deep
* @return char
*/
unsigned char getrandom8()
{
unsigned char si, sj;
rs.i = (rs.i + 1);
si = rs.s[rs.i];
rs.j = (rs.j + si);
sj = rs.s[rs.j];
rs.s[rs.i] = sj;
rs.s[rs.j] = si;
return (rs.s[(si + sj) & 0xff]);
}
/*************************************************************************/
/**
* Get the random numbers 16 byte deep
* @return char
*/
uint16 getrandom16()
{
uint16 val;
val = getrandom8() << 8;
val |= getrandom8();
return val;
}
/*************************************************************************/
/**
* Get the random numbers 32 byte deep
* @return char
*/
uint32 getrandom32()
{
uint32 val;
val = getrandom8() << 24;
val |= getrandom8() << 16;
val |= getrandom8() << 8;
val |= getrandom8();
return val;
}
/*************************************************************************/
/**
* Number of tokens in a string
* @param str String
* @param dilim Dilimiter
* @return number of tokens
*/
int myNumToken(const char *str, const char dilim)
{
int len, idx, counter = 0, start_pos = 0;
if (!str) {
return 0;
}
len = strlen(str);
for (idx = 0; idx <= len; idx++) {
if ((str[idx] == dilim) || (idx == len)) {
start_pos = idx + 1;
counter++;
}
}
return counter;
}
/*************************************************************************/
/**
* Resolve a host to an IP
* @param host to convert
* @return ip address
*/
char *host_resolve(char *host)
{
struct hostent *hentp = NULL;
uint32 ip = INADDR_NONE;
char ipbuf[16];
char *ipreturn;
struct in_addr addr;
ipreturn = NULL;
hentp = gethostbyname(host);
if (hentp) {
memcpy(&ip, hentp->h_addr, sizeof(hentp->h_length));
addr.s_addr = ip;
ntoa(addr, ipbuf, sizeof(ipbuf));
ipreturn = sstrdup(ipbuf);
if (debug) {
alog("debug: resolved %s to %s", host, ipbuf);
}
return ipreturn;
} else {
return ipreturn;
}
}
/*************************************************************************/
/**
* Change an unsigned string to a signed string, overwriting the original
* string.
* @param input string
* @return output string, same as input string.
*/
char *str_signed(unsigned char *str)
{
char *nstr;
nstr = reinterpret_cast<char *>(str);
while (*str) {
*nstr = static_cast<char>(*str);
str++;
nstr++;
}
return nstr;
}
/**
* Strip the mode prefix from the given string.
* Useful for using the modes stored in things like ircd->ownerset etc..
**/
char *stripModePrefix(const char *str)
{
if (str && ((*str == '+') || (*str == '-'))) {
return sstrdup(str + 1);
}
return NULL;
}
/* Equivalent to inet_ntoa */
void ntoa(struct in_addr addr, char *ipaddr, int len)
{
unsigned char *bytes = reinterpret_cast<unsigned char *>(&addr.s_addr);
snprintf(ipaddr, len, "%u.%u.%u.%u", bytes[0], bytes[1], bytes[2],
bytes[3]);
}
/**
* Build a string list from a given source string.
* This is usually used for parsing out values from the config file, but could
* be used for other things.
**/
char **buildStringList(const std::string &src, int *number)
{
int i = 0;
char **list = NULL;
spacesepstream tokens(src);
std::string token;
while (tokens.GetToken(token)) {
i++;
list = static_cast<char **>(realloc(list, sizeof(char *) * i));
list[i - 1] = sstrdup(token.c_str());
}
*number = i; /* always zero it, even if we have no setters */
return list;
}
/*
* strlcat and strlcpy were ripped from openssh 2.5.1p2
* They had the following Copyright info:
*
*
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
* INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HAVE_STRLCAT
size_t strlcat(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz, dlen;
while (n-- != 0 && *d != '\0')
d++;
dlen = d - dst;
n = siz - dlen;
if (n == 0)
return (dlen + strlen(s));
while (*s != '\0') {
if (n != 1) {
*d++ = *s;
n--;
}
s++;
}
*d = '\0';
return dlen + (s - src); /* count does not include NUL */
}
#endif
#ifndef HAVE_STRLCPY
size_t strlcpy(char *dst, const char *src, size_t siz)
{
char *d = dst;
const char *s = src;
size_t n = siz;
/* Copy as many bytes as will fit */
if (n != 0 && --n != 0) {
do {
if ((*d++ = *s++) == 0)
break;
}
while (--n != 0);
}
/* Not enough room in dst, add NUL and traverse rest of src */
if (n == 0) {
if (siz != 0)
*d = '\0'; /* NUL-terminate dst */
while (*s++);
}
return s - src - 1; /* count does not include NUL */
}
#endif
#ifdef _WIN32
char *GetWindowsVersion()
{
OSVERSIONINFOEX osvi;
BOOL bOsVersionInfoEx;
char buf[BUFSIZE];
char *extra;
char *cputype;
SYSTEM_INFO si;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
ZeroMemory(&si, sizeof(SYSTEM_INFO));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx((OSVERSIONINFO *) & osvi)) {
return sstrdup("");
}
}
GetSystemInfo(&si);
/* Determine CPU type 32 or 64 */
if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_AMD64 ) {
cputype = sstrdup(" 64-bit");
} else if (si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_INTEL ) {
cputype = sstrdup(" 32-bit");
} else if ( si.wProcessorArchitecture==PROCESSOR_ARCHITECTURE_IA64 ) {
cputype = sstrdup(" Itanium 64-bit");
} else {
cputype = sstrdup(" ");
}
switch (osvi.dwPlatformId) {
/* test for the Windows NT product family. */
case VER_PLATFORM_WIN32_NT:
/* Windows Vista or Windows Server 2008 */
if (osvi.dwMajorVersion == 6 && osvi.dwMinorVersion == 0) {
if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
extra = sstrdup("Enterprise Edition");
} else if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
extra = sstrdup("Datacenter Edition");
} else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
extra = sstrdup("Home Premium/Basic");
} else {
extra = sstrdup(" ");
}
if (osvi.wProductType & VER_NT_WORKSTATION) {
snprintf(buf, sizeof(buf), "Microsoft Windows Vista %s%s",
cputype, extra);
} else {
snprintf(buf, sizeof(buf), "Microsoft Windows Server 2008 %s%s",
cputype, extra);
}
delete [] extra;
}
/* Windows 2003 or Windows XP Pro 64 */
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 2) {
if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
extra = sstrdup("Datacenter Edition");
} else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
extra = sstrdup("Enterprise Edition");
#ifdef VER_SUITE_COMPUTE_SERVER
} else if (osvi.wSuiteMask & VER_SUITE_COMPUTE_SERVER) {
extra = sstrdup("Compute Cluster Edition");
#endif
} else if (osvi.wSuiteMask == VER_SUITE_BLADE) {
extra = sstrdup("Web Edition");
} else {
extra = sstrdup("Standard Edition");
}
if ( osvi.wProductType & VER_NT_WORKSTATION && si.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_AMD64) {
snprintf(buf, sizeof(buf), "Windows XP Professional x64 Edition %s",
extra);
} else {
snprintf(buf, sizeof(buf),
"Microsoft Windows Server 2003 Family %s%s", cputype, extra);
}
delete [] extra;
}
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 1) {
if (osvi.wSuiteMask & VER_SUITE_EMBEDDEDNT) {
extra = sstrdup("Embedded");
} else if (osvi.wSuiteMask & VER_SUITE_PERSONAL) {
extra = sstrdup("Home Edition");
} else {
extra = sstrdup(" ");
}
snprintf(buf, sizeof(buf), "Microsoft Windows XP %s", extra);
delete [] extra;
}
if (osvi.dwMajorVersion == 5 && osvi.dwMinorVersion == 0) {
if (osvi.wSuiteMask & VER_SUITE_DATACENTER) {
extra = sstrdup("Datacenter Server");
} else if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
extra = sstrdup("Advanced Server");
} else {
extra = sstrdup("Server");
}
snprintf(buf, sizeof(buf), "Microsoft Windows 2000 %s", extra);
delete [] extra;
}
if (osvi.dwMajorVersion <= 4) {
if (osvi.wSuiteMask & VER_SUITE_ENTERPRISE) {
extra = sstrdup("Server 4.0, Enterprise Edition");
} else {
extra = sstrdup("Server 4.0");
}
snprintf(buf, sizeof(buf), "Microsoft Windows NT %s", extra);
delete [] extra;
}
case VER_PLATFORM_WIN32_WINDOWS:
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 0) {
if (osvi.szCSDVersion[1] == 'C' || osvi.szCSDVersion[1] == 'B') {
extra = sstrdup("OSR2");
} else {
extra = sstrdup(" ");
}
snprintf(buf, sizeof(buf), "Microsoft Windows 95 %s", extra);
delete [] extra;
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 10) {
if (osvi.szCSDVersion[1] == 'A') {
extra = sstrdup("SE");
} else {
extra = sstrdup(" ");
}
snprintf(buf, sizeof(buf), "Microsoft Windows 98 %s", extra);
delete [] extra;
}
if (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion == 90) {
snprintf(buf, sizeof(buf),
"Microsoft Windows Millennium Edition");
}
}
delete [] cputype;
return sstrdup(buf);
}
int SupportedWindowsVersion()
{
OSVERSIONINFOEX osvi;
BOOL bOsVersionInfoEx;
ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX));
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
if (!(bOsVersionInfoEx = GetVersionEx((OSVERSIONINFO *) & osvi))) {
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
if (!GetVersionEx((OSVERSIONINFO *) & osvi)) {
return 0;
}
}
switch (osvi.dwPlatformId) {
/* test for the Windows NT product family. */
case VER_PLATFORM_WIN32_NT:
/* win nt4 */
if (osvi.dwMajorVersion <= 4) {
return 0;
}
/* the rest */
return 1;
/* win95 win98 winME */
case VER_PLATFORM_WIN32_WINDOWS:
return 0;
}
return 0;
}
#endif
/*************************************************************************/
/* This 2 functions were originally found in Bahamut */
/**
* Turn a cidr value into a netmask
* @param cidr CIDR value
* @return Netmask value
*/
uint32 cidr_to_netmask(uint16 cidr)
{
if (cidr == 0)
return 0;
return (0xFFFFFFFF - (1 << (32 - cidr)) + 1);
}
/**
* Turn a netmask into a cidr value
* @param mask Netmask
* @return CIDR value
*/
uint16 netmask_to_cidr(uint32 mask)
{
int tmp = 0;
while (!(mask & (1 << tmp)) && (tmp < 32))
tmp++;
return (32 - tmp);
}
/*************************************************************************/
/**
* Check if the given string is some sort of wildcard
* @param str String to check
* @return 1 for wildcard, 0 for anything else
*/
int str_is_wildcard(const char *str)
{
while (*str) {
if ((*str == '*') || (*str == '?'))
return 1;
str++;
}
return 0;
}
/**
* Check if the given string is a pure wildcard
* @param str String to check
* @return 1 for pure wildcard, 0 for anything else
*/
int str_is_pure_wildcard(const char *str)
{
while (*str) {
if (*str != '*')
return 0;
str++;
}
return 1;
}
/*************************************************************************/
/**
* Check if the given string is an IP, and return the IP.
* @param str String to check
* @return The IP, if one found. 0 if none.
*/
uint32 str_is_ip(char *str)
{
int i;
int octets[4] = { -1, -1, -1, -1 };
char *s = str;
uint32 ip;
for (i = 0; i < 4; i++) {
octets[i] = strtol(s, &s, 10);
/* Bail out if the octet is invalid or wrongly terminated */
if ((octets[i] < 0) || (octets[i] > 255)
|| ((i < 3) && (*s != '.')))
return 0;
if (i < 3)
s++;
}
/* Fill the IP - the dirty way */
ip = octets[3];
ip += octets[2] * 256;
ip += octets[1] * 65536;
ip += octets[0] * 16777216;
return ip;
}
/*************************************************************************/
/**
* Check if the given string is an IP or CIDR mask, and fill the given
* ip/cidr params if so.
* @param str String to check
* @param ip The ipmask to fill when a CIDR is found
* @param mask The CIDR mask to fill when a CIDR is found
* @param host Displayed host
* @return 1 for IP/CIDR, 0 for anything else
*/
int str_is_cidr(char *str, uint32 * ip, uint32 * mask, char **host)
{
int i;
int octets[4] = { -1, -1, -1, -1 };
char *s = str;
char buf[512];
uint16 cidr;
for (i = 0; i < 4; i++) {
octets[i] = strtol(s, &s, 10);
/* Bail out if the octet is invalid or wrongly terminated */
if ((octets[i] < 0) || (octets[i] > 255)
|| ((i < 3) && (*s != '.')))
return 0;
if (i < 3)
s++;
}
/* Fill the IP - the dirty way */
*ip = octets[3];
*ip += octets[2] * 256;
*ip += octets[1] * 65536;
*ip += octets[0] * 16777216;
if (*s == '/') {
s++;
/* There's a CIDR mask here! */
cidr = strtol(s, &s, 10);
/* Bail out if the CIDR is invalid or the string isn't done yet */
if ((cidr > 32) || (*s))
return 0;
} else {
/* No CIDR mask here - use 32 so the whole ip will be matched */
cidr = 32;
}
*mask = cidr_to_netmask(cidr);
/* Apply the mask to avoid 255.255.255.255/8 bans */
*ip &= *mask;
/* Refill the octets to fill the host */
octets[0] = (*ip & 0xFF000000) / 16777216;
octets[1] = (*ip & 0x00FF0000) / 65536;
octets[2] = (*ip & 0x0000FF00) / 256;
octets[3] = (*ip & 0x000000FF);
if (cidr == 32)
snprintf(buf, 512, "%d.%d.%d.%d", octets[0], octets[1], octets[2],
octets[3]);
else
snprintf(buf, 512, "%d.%d.%d.%d/%d", octets[0], octets[1],
octets[2], octets[3], cidr);
*host = sstrdup(buf);
return 1;
}
/* EOF */