diff --git a/doc/html/man5/3proxy.cfg.5.html b/doc/html/man5/3proxy.cfg.5.html index 297b3fb..9103b39 100644 --- a/doc/html/man5/3proxy.cfg.5.html +++ b/doc/html/man5/3proxy.cfg.5.html @@ -326,7 +326,11 @@ sets logfile for all gateways
@ (for Unix) use syslog, filename is used as ident name
& use ODBC, filename consists of comma-delimited datasource,username,password (username and password are -optional)
+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
radius - use RADIUS for logging
LOGTYPE is one of:
c
Minutely
diff --git a/man/3proxy.cfg.5 b/man/3proxy.cfg.5 index 778bc28..252b44d 100644 --- a/man/3proxy.cfg.5 +++ b/man/3proxy.cfg.5 @@ -325,7 +325,10 @@ proxy on a client with FTP proxy support. Username format is one of .br @ (for Unix) use syslog, filename is used as ident name .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 radius - use RADIUS for logging .br diff --git a/src/log.c b/src/log.c index a58006b..4f649dc 100644 --- a/src/log.c +++ b/src/log.c @@ -675,27 +675,67 @@ void loginit(void){ #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 - 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 *lg; - int err = 0; + const struct logtype *type; + const unsigned char *params; + size_t len; + int err = 0, changed; _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){ - if(!strcmp((char *)lg->selector, (char *)selector)){ + if(lg->type == type && !strncmp((char *)lg->selector, (char *)selector, len) && !lg->selector[len]){ lg->refs++; + changed = (params && lg->params)? strcmp((char *)params, (char *)lg->params) : (params != NULL || lg->params != NULL); _3proxy_mutex_unlock(&log_mutex); + if(changed) logsetparams(lg, params); return lg; } } - if(!(lg = calloc(1, sizeof(*lg))) || !(lg->selector = (unsigned char *)strdup((char *)selector))){ - if(lg) free(lg); + if(!(lg = calloc(1, sizeof(*lg))) || !(lg->selector = malloc(len + 1)) || + (params && !(lg->params = (unsigned char *)strdup((char *)params)))){ + if(lg){ + if(lg->selector) free(lg->selector); + free(lg); + } _3proxy_mutex_unlock(&log_mutex); errno = ENOMEM; return NULL; } - lg->type = logmatch(selector); + memcpy(lg->selector, selector, len); + lg->selector[len] = 0; + lg->type = type; lg->rotation = rotation; lg->rotated = time(NULL); _3proxy_mutex_init(&lg->mutex); @@ -708,6 +748,7 @@ struct logger *logget(const unsigned char *selector, ROTATION rotation){ err = errno; _3proxy_mutex_unlock(&log_mutex); _3proxy_mutex_destroy(&lg->mutex); + if(lg->params) free(lg->params); free(lg->selector); free(lg); errno = err; @@ -758,6 +799,7 @@ void logput(struct logger *lg){ if(lg->type->close) lg->type->close(lg); _3proxy_mutex_destroy(&lg->mutex); logfreearchiver(lg); + if(lg->params) free(lg->params); free(lg->selector); free(lg); } @@ -808,10 +850,10 @@ static void logfallback(struct logger *lg, struct clientparam *param, const unsi logput(to); } -/* The part of a log string fit to be shown: up to a comma, an ODBC string - going on with the user and the password, and at most 200 bytes. */ +/* The part of a log string fit to be shown: its name, without parameters + (an ODBC user and password), and at most 200 bytes. */ 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; } @@ -846,8 +888,7 @@ static void logwrite(struct logger *lg, struct clientparam *param, const unsigne if(report){ unsigned char msg[300]; - /* up to a comma: an ODBC string goes on with user and password */ - sprintf((char *)msg, "Log %.*s failed, its lines go to the error log", (int)logselen(lg->selector), lg->selector); + sprintf((char *)msg, "Log %.200s failed, its lines go to the error log", lg->selector); logerror(msg); } } diff --git a/src/sql.c b/src/sql.c index 30e4388..4a92e0d 100644 --- a/src/sql.c +++ b/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){ struct logodbc *d = (struct logodbc *)lg->data; SQLRETURN retcode; char * datasource; - char * username; - char * password; - char * string; + char * username = NULL; + char * password = NULL; + char * string = NULL; + size_t slen = 0; if(d->hstmt || d->hdbc || d->henv) odbcdisconnect(d); if(!d->henv){ @@ -58,20 +61,24 @@ static int odbcconnect(struct logger *lg){ } SQLSetConnectAttr(d->hdbc, SQL_LOGIN_TIMEOUT, (void*)15, 0); } - string = strdup((char *)lg->selector + 1); - if(!string) return 0; - datasource = strtok(string, ","); - username = strtok(NULL, ","); - password = strtok(NULL, ","); - if(!datasource) datasource = ""; - + datasource = (char *)lg->selector + 1; + if(lg->params){ + if(!(string = strdup((char *)lg->params))) return 0; + slen = strlen(string); + username = string; + if((password = strchr(string, ','))) *password++ = 0; + } /* Connect to data source */ retcode = SQLConnect(d->hdbc, (SQLCHAR*) datasource, (SQLSMALLINT)strlen(datasource), (SQLCHAR*) username, (SQLSMALLINT)((username)?strlen(username):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){ SQLFreeHandle(SQL_HANDLE_DBC, d->hdbc); d->hdbc = NULL; @@ -125,7 +132,7 @@ static void odbcclose(struct logger *lg){ } 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 diff --git a/src/structures.h b/src/structures.h index 493e1d1..c932db2 100644 --- a/src/structures.h +++ b/src/structures.h @@ -627,7 +627,9 @@ struct hashtable { /* A log, named by the string the log command or -l gives it: "" standard 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, the standard ones (none, standard output and error, syslog) excepted. */ struct logtype { @@ -647,12 +649,14 @@ struct logtype { int stacksize; /* the client thread stack its writing needs */ int standard; /* kept open for the life of the process */ int text; /* writes a line of text: errors can go there */ + int params; /* the string after a comma is parameters */ }; struct logger { struct logger *next; 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 */ int refs; int errors; /* writes failed in a row */