mirror of
https://github.com/3proxy/3proxy.git
synced 2026-10-28 22:05:48 +08:00
Logs: an ODBC log named by its data source, user and password its parameters
The string up to the first comma names an ODBC log; the user and the password are kept apart as its parameters, never shown, and do not tell logs apart. Another log or -l naming the same data source with other parameters gives them to the logger, which reconnects with them. The password is whatever follows the comma after the user. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
e87ffcd7e1
commit
477a2d3822
@ -326,7 +326,11 @@ sets logfile for all gateways <br>
|
|||||||
@ (for Unix) use syslog, filename is used as ident name <br>
|
@ (for Unix) use syslog, filename is used as ident name <br>
|
||||||
& use ODBC, filename consists of comma-delimited
|
& use ODBC, filename consists of comma-delimited
|
||||||
datasource,username,password (username and password are
|
datasource,username,password (username and password are
|
||||||
optional) <br>
|
optional; the password is everything after the second comma).
|
||||||
|
The datasource alone names the log: the username and password
|
||||||
|
are its parameters, never shown in messages, and a later log
|
||||||
|
or -l with the same datasource and other parameters reconnects
|
||||||
|
the log with them <br>
|
||||||
radius - use RADIUS for logging <br>
|
radius - use RADIUS for logging <br>
|
||||||
LOGTYPE is one of: <b><br>
|
LOGTYPE is one of: <b><br>
|
||||||
c</b> Minutely <b><br>
|
c</b> Minutely <b><br>
|
||||||
|
|||||||
@ -325,7 +325,10 @@ proxy on a client with FTP proxy support. Username format is one of
|
|||||||
.br
|
.br
|
||||||
@ (for Unix) use syslog, filename is used as ident name
|
@ (for Unix) use syslog, filename is used as ident name
|
||||||
.br
|
.br
|
||||||
& use ODBC, filename consists of comma-delimited datasource,username,password (username and password are optional)
|
& use ODBC, filename consists of comma-delimited datasource,username,password (username and password are optional;
|
||||||
|
the password is everything after the second comma). The datasource alone names the log: the username and password
|
||||||
|
are its parameters, never shown in messages, and a later log or -l with the same datasource and other parameters
|
||||||
|
reconnects the log with them
|
||||||
.br
|
.br
|
||||||
radius - use RADIUS for logging
|
radius - use RADIUS for logging
|
||||||
.br
|
.br
|
||||||
|
|||||||
63
src/log.c
63
src/log.c
@ -675,27 +675,67 @@ void loginit(void){
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* The length of the name in a log string: for a type with parameters up to
|
||||||
|
the comma they follow. */
|
||||||
|
static size_t lognamelen(const struct logtype *type, const unsigned char *selector){
|
||||||
|
return type->params? strcspn((char *)selector, ",") : strlen((char *)selector);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Parameters which differ from those a logger has: given to it, and the
|
||||||
|
logger opened again with them. Called holding a reference. */
|
||||||
|
static void logsetparams(struct logger *lg, const unsigned char *params){
|
||||||
|
unsigned char *p = NULL;
|
||||||
|
|
||||||
|
if(params && !(p = (unsigned char *)strdup((char *)params))) return;
|
||||||
|
_3proxy_mutex_lock(&lg->mutex);
|
||||||
|
if(lg->params) free(lg->params);
|
||||||
|
lg->params = p;
|
||||||
|
if(lg->type->close) lg->type->close(lg);
|
||||||
|
lg->errors = 0;
|
||||||
|
lg->failed = 0;
|
||||||
|
if(lg->type->init && lg->type->init(lg)){
|
||||||
|
lg->failed = 1;
|
||||||
|
lg->failtime = time(NULL);
|
||||||
|
}
|
||||||
|
_3proxy_mutex_unlock(&lg->mutex);
|
||||||
|
}
|
||||||
|
|
||||||
/* The logger named so, opened if none is: held until logput(). NULL, with
|
/* The logger named so, opened if none is: held until logput(). NULL, with
|
||||||
errno set, if it cannot be opened. */
|
errno set, if it cannot be opened. A logger found with other parameters
|
||||||
|
takes the new ones. */
|
||||||
struct logger *logget(const unsigned char *selector, ROTATION rotation){
|
struct logger *logget(const unsigned char *selector, ROTATION rotation){
|
||||||
struct logger *lg;
|
struct logger *lg;
|
||||||
int err = 0;
|
const struct logtype *type;
|
||||||
|
const unsigned char *params;
|
||||||
|
size_t len;
|
||||||
|
int err = 0, changed;
|
||||||
|
|
||||||
_3proxy_mutex_lock(&log_mutex);
|
_3proxy_mutex_lock(&log_mutex);
|
||||||
|
type = logmatch(selector);
|
||||||
|
len = lognamelen(type, selector);
|
||||||
|
params = selector[len]? selector + len + 1 : NULL;
|
||||||
for(lg = loggers; lg; lg = lg->next){
|
for(lg = loggers; lg; lg = lg->next){
|
||||||
if(!strcmp((char *)lg->selector, (char *)selector)){
|
if(lg->type == type && !strncmp((char *)lg->selector, (char *)selector, len) && !lg->selector[len]){
|
||||||
lg->refs++;
|
lg->refs++;
|
||||||
|
changed = (params && lg->params)? strcmp((char *)params, (char *)lg->params) : (params != NULL || lg->params != NULL);
|
||||||
_3proxy_mutex_unlock(&log_mutex);
|
_3proxy_mutex_unlock(&log_mutex);
|
||||||
|
if(changed) logsetparams(lg, params);
|
||||||
return lg;
|
return lg;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(!(lg = calloc(1, sizeof(*lg))) || !(lg->selector = (unsigned char *)strdup((char *)selector))){
|
if(!(lg = calloc(1, sizeof(*lg))) || !(lg->selector = malloc(len + 1)) ||
|
||||||
if(lg) free(lg);
|
(params && !(lg->params = (unsigned char *)strdup((char *)params)))){
|
||||||
|
if(lg){
|
||||||
|
if(lg->selector) free(lg->selector);
|
||||||
|
free(lg);
|
||||||
|
}
|
||||||
_3proxy_mutex_unlock(&log_mutex);
|
_3proxy_mutex_unlock(&log_mutex);
|
||||||
errno = ENOMEM;
|
errno = ENOMEM;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
lg->type = logmatch(selector);
|
memcpy(lg->selector, selector, len);
|
||||||
|
lg->selector[len] = 0;
|
||||||
|
lg->type = type;
|
||||||
lg->rotation = rotation;
|
lg->rotation = rotation;
|
||||||
lg->rotated = time(NULL);
|
lg->rotated = time(NULL);
|
||||||
_3proxy_mutex_init(&lg->mutex);
|
_3proxy_mutex_init(&lg->mutex);
|
||||||
@ -708,6 +748,7 @@ struct logger *logget(const unsigned char *selector, ROTATION rotation){
|
|||||||
err = errno;
|
err = errno;
|
||||||
_3proxy_mutex_unlock(&log_mutex);
|
_3proxy_mutex_unlock(&log_mutex);
|
||||||
_3proxy_mutex_destroy(&lg->mutex);
|
_3proxy_mutex_destroy(&lg->mutex);
|
||||||
|
if(lg->params) free(lg->params);
|
||||||
free(lg->selector);
|
free(lg->selector);
|
||||||
free(lg);
|
free(lg);
|
||||||
errno = err;
|
errno = err;
|
||||||
@ -758,6 +799,7 @@ void logput(struct logger *lg){
|
|||||||
if(lg->type->close) lg->type->close(lg);
|
if(lg->type->close) lg->type->close(lg);
|
||||||
_3proxy_mutex_destroy(&lg->mutex);
|
_3proxy_mutex_destroy(&lg->mutex);
|
||||||
logfreearchiver(lg);
|
logfreearchiver(lg);
|
||||||
|
if(lg->params) free(lg->params);
|
||||||
free(lg->selector);
|
free(lg->selector);
|
||||||
free(lg);
|
free(lg);
|
||||||
}
|
}
|
||||||
@ -808,10 +850,10 @@ static void logfallback(struct logger *lg, struct clientparam *param, const unsi
|
|||||||
logput(to);
|
logput(to);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The part of a log string fit to be shown: up to a comma, an ODBC string
|
/* The part of a log string fit to be shown: its name, without parameters
|
||||||
going on with the user and the password, and at most 200 bytes. */
|
(an ODBC user and password), and at most 200 bytes. */
|
||||||
size_t logselen(const unsigned char *selector){
|
size_t logselen(const unsigned char *selector){
|
||||||
size_t len = strcspn((char *)selector, ",");
|
size_t len = lognamelen(logmatch(selector), selector);
|
||||||
|
|
||||||
return len > 200? 200 : len;
|
return len > 200? 200 : len;
|
||||||
}
|
}
|
||||||
@ -846,8 +888,7 @@ static void logwrite(struct logger *lg, struct clientparam *param, const unsigne
|
|||||||
if(report){
|
if(report){
|
||||||
unsigned char msg[300];
|
unsigned char msg[300];
|
||||||
|
|
||||||
/* up to a comma: an ODBC string goes on with user and password */
|
sprintf((char *)msg, "Log %.200s failed, its lines go to the error log", lg->selector);
|
||||||
sprintf((char *)msg, "Log %.*s failed, its lines go to the error log", (int)logselen(lg->selector), lg->selector);
|
|
||||||
logerror(msg);
|
logerror(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
33
src/sql.c
33
src/sql.c
@ -26,14 +26,17 @@ static void odbcdisconnect(struct logodbc *d){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* &DATASOURCE,USERNAME,PASSWORD */
|
/* The log string is &DATASOURCE,USERNAME,PASSWORD. The data source
|
||||||
|
alone names the log; user and password are its parameters, the
|
||||||
|
password being whatever follows the comma after the user. */
|
||||||
static int odbcconnect(struct logger *lg){
|
static int odbcconnect(struct logger *lg){
|
||||||
struct logodbc *d = (struct logodbc *)lg->data;
|
struct logodbc *d = (struct logodbc *)lg->data;
|
||||||
SQLRETURN retcode;
|
SQLRETURN retcode;
|
||||||
char * datasource;
|
char * datasource;
|
||||||
char * username;
|
char * username = NULL;
|
||||||
char * password;
|
char * password = NULL;
|
||||||
char * string;
|
char * string = NULL;
|
||||||
|
size_t slen = 0;
|
||||||
|
|
||||||
if(d->hstmt || d->hdbc || d->henv) odbcdisconnect(d);
|
if(d->hstmt || d->hdbc || d->henv) odbcdisconnect(d);
|
||||||
if(!d->henv){
|
if(!d->henv){
|
||||||
@ -58,20 +61,24 @@ static int odbcconnect(struct logger *lg){
|
|||||||
}
|
}
|
||||||
SQLSetConnectAttr(d->hdbc, SQL_LOGIN_TIMEOUT, (void*)15, 0);
|
SQLSetConnectAttr(d->hdbc, SQL_LOGIN_TIMEOUT, (void*)15, 0);
|
||||||
}
|
}
|
||||||
string = strdup((char *)lg->selector + 1);
|
datasource = (char *)lg->selector + 1;
|
||||||
if(!string) return 0;
|
if(lg->params){
|
||||||
datasource = strtok(string, ",");
|
if(!(string = strdup((char *)lg->params))) return 0;
|
||||||
username = strtok(NULL, ",");
|
slen = strlen(string);
|
||||||
password = strtok(NULL, ",");
|
username = string;
|
||||||
if(!datasource) datasource = "";
|
if((password = strchr(string, ','))) *password++ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Connect to data source */
|
/* Connect to data source */
|
||||||
retcode = SQLConnect(d->hdbc, (SQLCHAR*) datasource, (SQLSMALLINT)strlen(datasource),
|
retcode = SQLConnect(d->hdbc, (SQLCHAR*) datasource, (SQLSMALLINT)strlen(datasource),
|
||||||
(SQLCHAR*) username, (SQLSMALLINT)((username)?strlen(username):0),
|
(SQLCHAR*) username, (SQLSMALLINT)((username)?strlen(username):0),
|
||||||
(SQLCHAR*) password, (SQLSMALLINT)((password)?strlen(password):0));
|
(SQLCHAR*) password, (SQLSMALLINT)((password)?strlen(password):0));
|
||||||
|
|
||||||
free(string);
|
if(string) {
|
||||||
|
/* no copy of the password left behind */
|
||||||
|
memset(string, 0, slen);
|
||||||
|
free(string);
|
||||||
|
}
|
||||||
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO){
|
if (retcode != SQL_SUCCESS && retcode != SQL_SUCCESS_WITH_INFO){
|
||||||
SQLFreeHandle(SQL_HANDLE_DBC, d->hdbc);
|
SQLFreeHandle(SQL_HANDLE_DBC, d->hdbc);
|
||||||
d->hdbc = NULL;
|
d->hdbc = NULL;
|
||||||
@ -125,7 +132,7 @@ static void odbcclose(struct logger *lg){
|
|||||||
}
|
}
|
||||||
|
|
||||||
const struct logtype logtype_odbc = {
|
const struct logtype logtype_odbc = {
|
||||||
"odbc", odbcmatch, odbcinit, odbcformat, odbcwrite, odbcclose, NULL, LOGSTACKSIZE, 0, 0
|
"odbc", odbcmatch, odbcinit, odbcformat, odbcwrite, odbcclose, NULL, LOGSTACKSIZE, 0, 0, 1
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@ -627,7 +627,9 @@ struct hashtable {
|
|||||||
|
|
||||||
/* A log, named by the string the log command or -l gives it: "" standard
|
/* A log, named by the string the log command or -l gives it: "" standard
|
||||||
output, "/dev/null" none, "@IDENT" syslog, "&DSN" ODBC, "radius" RADIUS
|
output, "/dev/null" none, "@IDENT" syslog, "&DSN" ODBC, "radius" RADIUS
|
||||||
accounting, anything else a file. One logger serves every service and
|
accounting, anything else a file. For a type with parameters, ODBC, the
|
||||||
|
string up to its first comma names the log and the rest, user and
|
||||||
|
password, are its parameters, neither shown nor telling logs apart. One logger serves every service and
|
||||||
configuration naming it the same way, and is closed once none uses it,
|
configuration naming it the same way, and is closed once none uses it,
|
||||||
the standard ones (none, standard output and error, syslog) excepted. */
|
the standard ones (none, standard output and error, syslog) excepted. */
|
||||||
struct logtype {
|
struct logtype {
|
||||||
@ -647,12 +649,14 @@ struct logtype {
|
|||||||
int stacksize; /* the client thread stack its writing needs */
|
int stacksize; /* the client thread stack its writing needs */
|
||||||
int standard; /* kept open for the life of the process */
|
int standard; /* kept open for the life of the process */
|
||||||
int text; /* writes a line of text: errors can go there */
|
int text; /* writes a line of text: errors can go there */
|
||||||
|
int params; /* the string after a comma is parameters */
|
||||||
};
|
};
|
||||||
|
|
||||||
struct logger {
|
struct logger {
|
||||||
struct logger *next;
|
struct logger *next;
|
||||||
const struct logtype *type;
|
const struct logtype *type;
|
||||||
unsigned char *selector;
|
unsigned char *selector; /* the name, without parameters */
|
||||||
|
unsigned char *params; /* what follows the name's comma, or NULL */
|
||||||
void *data; /* the type's own */
|
void *data; /* the type's own */
|
||||||
int refs;
|
int refs;
|
||||||
int errors; /* writes failed in a row */
|
int errors; /* writes failed in a row */
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user