diff options
Diffstat (limited to 'mod_log_sql.c')
| -rw-r--r-- | mod_log_sql.c | 1687 |
1 files changed, 0 insertions, 1687 deletions
diff --git a/mod_log_sql.c b/mod_log_sql.c deleted file mode 100644 index f02243e..0000000 --- a/mod_log_sql.c +++ /dev/null | |||
| @@ -1,1687 +0,0 @@ | |||
| 1 | |||
| 2 | /* --------* | ||
| 3 | * DEFINES * | ||
| 4 | * --------*/ | ||
| 5 | |||
| 6 | /* The enduser may wish to modify this */ | ||
| 7 | #undef DEBUG | ||
| 8 | |||
| 9 | /* The enduser won't modify these */ | ||
| 10 | #define MYSQL_ERROR(mysql) ((mysql)?(mysql_error(mysql)):"MySQL server has gone away") | ||
| 11 | #define ERRLEVEL APLOG_ERR|APLOG_NOERRNO | ||
| 12 | #define WARNINGLEVEL APLOG_WARNING|APLOG_NOERRNO | ||
| 13 | #define NOTICELEVEL APLOG_NOTICE|APLOG_NOERRNO | ||
| 14 | #define DEBUGLEVEL APLOG_DEBUG|APLOG_NOERRNO | ||
| 15 | |||
| 16 | /* ---------* | ||
| 17 | * INCLUDES * | ||
| 18 | * ---------*/ | ||
| 19 | #include <time.h> | ||
| 20 | #include <stdio.h> | ||
| 21 | #include <stdlib.h> | ||
| 22 | #include <string.h> | ||
| 23 | #include "httpd.h" | ||
| 24 | #include "http_config.h" | ||
| 25 | #include "http_log.h" | ||
| 26 | #include "http_core.h" | ||
| 27 | #include "mysql.h" | ||
| 28 | #include "mysqld_error.h" | ||
| 29 | |||
| 30 | #if MODULE_MAGIC_NUMBER >= 19980324 /* M_M_N is defined in /usr/local/Apache/include/ap_mmn.h, 19990320 as of this writing. */ | ||
| 31 | #include "ap_compat.h" | ||
| 32 | #endif | ||
| 33 | |||
| 34 | #ifdef WANT_SSL_LOGGING | ||
| 35 | #include "mod_ssl.h" | ||
| 36 | #endif | ||
| 37 | |||
| 38 | |||
| 39 | /* -------------* | ||
| 40 | * DECLARATIONS * | ||
| 41 | * -------------*/ | ||
| 42 | |||
| 43 | /* Declare ourselves so the configuration routines can find and know us. */ | ||
| 44 | module sql_log_module; | ||
| 45 | |||
| 46 | /* The contents of these are known 'Apache wide' and are not variable | ||
| 47 | * on a per-virtual-server basis. Every virtual server 'knows' the | ||
| 48 | * same versions of these variables. | ||
| 49 | */ | ||
| 50 | MYSQL logsql_server, *logsql_server_p = NULL; | ||
| 51 | |||
| 52 | int logsql_massvirtual = 0; | ||
| 53 | int logsql_createtables = 0; | ||
| 54 | int logsql_forcepreserve = 0; | ||
| 55 | char *logsql_dbname = NULL; | ||
| 56 | char *logsql_dbhost = NULL; | ||
| 57 | char *logsql_dbuser = NULL; | ||
| 58 | char *logsql_dbpwd = NULL; | ||
| 59 | char *logsql_machid = NULL; | ||
| 60 | char *logsql_socketfile = "/tmp/mysql.sock"; | ||
| 61 | unsigned int logsql_tcpport = 3306; | ||
| 62 | |||
| 63 | #ifdef WANT_DELAYED_MYSQL_INSERT | ||
| 64 | char *logsql_insertclause = "insert delayed into "; | ||
| 65 | #else | ||
| 66 | char *logsql_insertclause = "insert into "; | ||
| 67 | #endif | ||
| 68 | |||
| 69 | typedef const char *(*item_key_func) (request_rec *, char *); | ||
| 70 | |||
| 71 | /* But the contents of this structure will vary by virtual server. | ||
| 72 | * This permits each virtual server to vary its configuration slightly | ||
| 73 | * for per-server customization. | ||
| 74 | * | ||
| 75 | * Each child process has its own segregated copy of this structure. | ||
| 76 | */ | ||
| 77 | typedef struct { | ||
| 78 | array_header *transfer_ignore_list; | ||
| 79 | array_header *transfer_accept_list; | ||
| 80 | array_header *remhost_ignore_list; | ||
| 81 | array_header *notes_list; | ||
| 82 | array_header *hout_list; | ||
| 83 | array_header *hin_list; | ||
| 84 | array_header *cookie_list; | ||
| 85 | char *notes_table_name; | ||
| 86 | char *hout_table_name; | ||
| 87 | char *hin_table_name; | ||
| 88 | char *cookie_table_name; | ||
| 89 | char *transfer_table_name; | ||
| 90 | char *transfer_log_format; | ||
| 91 | char *preserve_file; | ||
| 92 | char *cookie_name; | ||
| 93 | } logsql_state; | ||
| 94 | |||
| 95 | |||
| 96 | /* -----------------* | ||
| 97 | * HELPER FUNCTIONS * | ||
| 98 | * -----------------*/ | ||
| 99 | |||
| 100 | int safe_create_tables(logsql_state *cls, request_rec *r); | ||
| 101 | |||
| 102 | static char *format_integer(pool *p, int i) | ||
| 103 | { | ||
| 104 | char dummy[40]; | ||
| 105 | ap_snprintf(dummy, sizeof(dummy), "%d", i); | ||
| 106 | return pstrdup(p, dummy); | ||
| 107 | } | ||
| 108 | |||
| 109 | static char *pfmt(pool *p, int i) | ||
| 110 | { | ||
| 111 | if (i <= 0) { | ||
| 112 | return "-"; | ||
| 113 | } else { | ||
| 114 | return format_integer(p, i); | ||
| 115 | } | ||
| 116 | } | ||
| 117 | |||
| 118 | /* Begin the individual functions that, given a request r, | ||
| 119 | * extract the needed information from it and return the | ||
| 120 | * value to the calling entity. | ||
| 121 | */ | ||
| 122 | |||
| 123 | static const char *extract_remote_host(request_rec *r, char *a) | ||
| 124 | { | ||
| 125 | return (char *) get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); | ||
| 126 | } | ||
| 127 | |||
| 128 | static const char *extract_remote_logname(request_rec *r, char *a) | ||
| 129 | { | ||
| 130 | return (char *) get_remote_logname(r); | ||
| 131 | } | ||
| 132 | |||
| 133 | static const char *extract_remote_user(request_rec *r, char *a) | ||
| 134 | { | ||
| 135 | char *rvalue = r->connection->user; | ||
| 136 | |||
| 137 | if (rvalue == NULL) { | ||
| 138 | rvalue = "-"; | ||
| 139 | } else if (strlen(rvalue) == 0) { | ||
| 140 | rvalue = "\"\""; | ||
| 141 | } | ||
| 142 | return rvalue; | ||
| 143 | } | ||
| 144 | |||
| 145 | #ifdef WANT_SSL_LOGGING | ||
| 146 | static const char *extract_ssl_keysize(request_rec *r, char *a) | ||
| 147 | { | ||
| 148 | char *result = NULL; | ||
| 149 | |||
| 150 | if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) { | ||
| 151 | result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_USEKEYSIZE"); | ||
| 152 | #ifdef DEBUG | ||
| 153 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"SSL_KEYSIZE: %s", result); | ||
| 154 | #endif | ||
| 155 | if (result != NULL && result[0] == '\0') | ||
| 156 | result = NULL; | ||
| 157 | return result; | ||
| 158 | } else { | ||
| 159 | return "0"; | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | static const char *extract_ssl_maxkeysize(request_rec *r, char *a) | ||
| 164 | { | ||
| 165 | char *result = NULL; | ||
| 166 | |||
| 167 | if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) { | ||
| 168 | result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER_ALGKEYSIZE"); | ||
| 169 | #ifdef DEBUG | ||
| 170 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"SSL_ALGKEYSIZE: %s", result); | ||
| 171 | #endif | ||
| 172 | if (result != NULL && result[0] == '\0') | ||
| 173 | result = NULL; | ||
| 174 | return result; | ||
| 175 | } else { | ||
| 176 | return "0"; | ||
| 177 | } | ||
| 178 | } | ||
| 179 | |||
| 180 | static const char *extract_ssl_cipher(request_rec *r, char *a) | ||
| 181 | { | ||
| 182 | char *result = NULL; | ||
| 183 | |||
| 184 | if (ap_ctx_get(r->connection->client->ctx, "ssl") != NULL) { | ||
| 185 | result = ssl_var_lookup(r->pool, r->server, r->connection, r, "SSL_CIPHER"); | ||
| 186 | #ifdef DEBUG | ||
| 187 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"SSL_CIPHER: %s", result); | ||
| 188 | #endif | ||
| 189 | if (result != NULL && result[0] == '\0') | ||
| 190 | result = NULL; | ||
| 191 | return result; | ||
| 192 | } else { | ||
| 193 | return "-"; | ||
| 194 | } | ||
| 195 | } | ||
| 196 | #endif /* WANT_SSL_LOGGING */ | ||
| 197 | |||
| 198 | static const char *extract_request_method(request_rec *r, char *a) | ||
| 199 | { | ||
| 200 | return r->method; | ||
| 201 | } | ||
| 202 | |||
| 203 | static const char *extract_request_protocol(request_rec *r, char *a) | ||
| 204 | { | ||
| 205 | return r->protocol; | ||
| 206 | } | ||
| 207 | |||
| 208 | static const char *extract_request_line(request_rec *r, char *a) | ||
| 209 | { | ||
| 210 | return r->the_request; | ||
| 211 | } | ||
| 212 | |||
| 213 | static const char *extract_request_file(request_rec *r, char *a) | ||
| 214 | { | ||
| 215 | return r->filename; | ||
| 216 | } | ||
| 217 | |||
| 218 | static const char *extract_request_uri(request_rec *r, char *a) | ||
| 219 | { | ||
| 220 | return r->uri; | ||
| 221 | } | ||
| 222 | |||
| 223 | static const char *extract_request_args(request_rec *r, char *a) | ||
| 224 | { | ||
| 225 | return r->args; | ||
| 226 | } | ||
| 227 | |||
| 228 | static const char *extract_status(request_rec *r, char *a) | ||
| 229 | { | ||
| 230 | return pfmt(r->pool, r->status); | ||
| 231 | } | ||
| 232 | |||
| 233 | static const char *extract_bytes_sent(request_rec *r, char *a) | ||
| 234 | { | ||
| 235 | if (!r->sent_bodyct) { | ||
| 236 | return "-"; | ||
| 237 | } else { | ||
| 238 | long int bs; | ||
| 239 | char dummy[40]; | ||
| 240 | bgetopt(r->connection->client, BO_BYTECT, &bs); | ||
| 241 | ap_snprintf(dummy, sizeof(dummy), "%ld", bs); | ||
| 242 | return pstrdup(r->pool, dummy); | ||
| 243 | } | ||
| 244 | } | ||
| 245 | |||
| 246 | /* | ||
| 247 | static const char *extract_header_in(request_rec *r, char *a) | ||
| 248 | { | ||
| 249 | return table_get(r->headers_in, a); | ||
| 250 | } | ||
| 251 | |||
| 252 | static const char *extract_header_out(request_rec *r, char *a) | ||
| 253 | { | ||
| 254 | const char *cp = table_get(r->headers_out, a); | ||
| 255 | if (!strcasecmp(a, "Content-type") && r->content_type) { | ||
| 256 | cp = r->content_type; | ||
| 257 | } | ||
| 258 | if (cp) { | ||
| 259 | return cp; | ||
| 260 | } | ||
| 261 | return table_get(r->err_headers_out, a); | ||
| 262 | } | ||
| 263 | */ | ||
| 264 | |||
| 265 | static const char *extract_request_time(request_rec *r, char *a) | ||
| 266 | { | ||
| 267 | int timz; | ||
| 268 | struct tm *t; | ||
| 269 | char tstr[MAX_STRING_LEN]; | ||
| 270 | |||
| 271 | t = get_gmtoff(&timz); | ||
| 272 | |||
| 273 | if (a && *a) { /* Custom format */ | ||
| 274 | strftime(tstr, MAX_STRING_LEN, a, t); | ||
| 275 | } else { /* CLF format */ | ||
| 276 | char sign = (timz < 0 ? '-' : '+'); | ||
| 277 | |||
| 278 | if (timz < 0) { | ||
| 279 | timz = -timz; | ||
| 280 | } | ||
| 281 | strftime(tstr, MAX_STRING_LEN, "[%d/%b/%Y:%H:%M:%S ", t); | ||
| 282 | ap_snprintf(tstr + strlen(tstr), sizeof(tstr) - strlen(tstr), "%c%.2d%.2d]", sign, timz / 60, timz % 60); | ||
| 283 | } | ||
| 284 | |||
| 285 | return pstrdup(r->pool, tstr); | ||
| 286 | } | ||
| 287 | |||
| 288 | static const char *extract_request_duration(request_rec *r, char *a) | ||
| 289 | { | ||
| 290 | char duration[22]; /* Long enough for 2^64 */ | ||
| 291 | |||
| 292 | ap_snprintf(duration, sizeof(duration), "%ld", time(NULL) - r->request_time); | ||
| 293 | return pstrdup(r->pool, duration); | ||
| 294 | } | ||
| 295 | |||
| 296 | static const char *extract_virtual_host(request_rec *r, char *a) | ||
| 297 | { | ||
| 298 | return ap_get_server_name(r); | ||
| 299 | } | ||
| 300 | |||
| 301 | static const char *extract_machine_id(request_rec *r, char *a) | ||
| 302 | { | ||
| 303 | if (!logsql_machid) | ||
| 304 | return "-"; | ||
| 305 | else | ||
| 306 | return logsql_machid; | ||
| 307 | } | ||
| 308 | |||
| 309 | static const char *extract_server_port(request_rec *r, char *a) | ||
| 310 | { | ||
| 311 | char portnum[22]; | ||
| 312 | |||
| 313 | ap_snprintf(portnum, sizeof(portnum), "%u", r->server->port); | ||
| 314 | return pstrdup(r->pool, portnum); | ||
| 315 | } | ||
| 316 | |||
| 317 | static const char *extract_child_pid(request_rec *r, char *a) | ||
| 318 | { | ||
| 319 | char pidnum[22]; | ||
| 320 | ap_snprintf(pidnum, sizeof(pidnum), "%ld", (long) getpid()); | ||
| 321 | return pstrdup(r->pool, pidnum); | ||
| 322 | } | ||
| 323 | |||
| 324 | static const char *extract_referer(request_rec *r, char *a) | ||
| 325 | { | ||
| 326 | const char *tempref; | ||
| 327 | |||
| 328 | tempref = table_get(r->headers_in, "Referer"); | ||
| 329 | if (!tempref) | ||
| 330 | { | ||
| 331 | return "-"; | ||
| 332 | } else { | ||
| 333 | return tempref; | ||
| 334 | } | ||
| 335 | } | ||
| 336 | |||
| 337 | static const char *extract_agent(request_rec *r, char *a) | ||
| 338 | { | ||
| 339 | const char *tempag; | ||
| 340 | |||
| 341 | tempag = table_get(r->headers_in, "User-Agent"); | ||
| 342 | if (!tempag) | ||
| 343 | { | ||
| 344 | return "-"; | ||
| 345 | } else { | ||
| 346 | return tempag; | ||
| 347 | } | ||
| 348 | } | ||
| 349 | |||
| 350 | static const char *extract_cookie(request_rec *r, char *a) | ||
| 351 | { | ||
| 352 | const char *cookiestr; | ||
| 353 | char *cookieend; | ||
| 354 | char *isvalid; | ||
| 355 | char *cookiebuf; | ||
| 356 | |||
| 357 | logsql_state *cls = get_module_config(r->server->module_config, &sql_log_module); | ||
| 358 | |||
| 359 | if (cls->cookie_name != NULL) { | ||
| 360 | #ifdef DEBUG | ||
| 361 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"watching for cookie '%s'", cls->cookie_name); | ||
| 362 | #endif | ||
| 363 | |||
| 364 | /* Fetch out the cookie header */ | ||
| 365 | cookiestr = (char *)table_get(r->headers_in, "cookie2"); | ||
| 366 | if (cookiestr != NULL) { | ||
| 367 | #ifdef DEBUG | ||
| 368 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie2: [%s]", cookiestr); | ||
| 369 | #endif | ||
| 370 | /* Does the cookie string contain one with our name? */ | ||
| 371 | isvalid = strstr(cookiestr, cls->cookie_name); | ||
| 372 | if (isvalid != NULL) { | ||
| 373 | /* Move past the cookie name and equal sign */ | ||
| 374 | isvalid += strlen(cls->cookie_name) + 1; | ||
| 375 | /* Duplicate it into the pool */ | ||
| 376 | cookiebuf = ap_pstrdup(r->pool, isvalid); | ||
| 377 | /* Segregate just this cookie out of the string | ||
| 378 | * with a terminating nul at the first semicolon */ | ||
| 379 | cookieend = strchr(cookiebuf, ';'); | ||
| 380 | if (cookieend != NULL) | ||
| 381 | *cookieend = '\0'; | ||
| 382 | return cookiebuf; | ||
| 383 | } | ||
| 384 | } | ||
| 385 | |||
| 386 | cookiestr = (char *)table_get(r->headers_in, "cookie"); | ||
| 387 | if (cookiestr != NULL) { | ||
| 388 | #ifdef DEBUG | ||
| 389 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie: [%s]", cookiestr); | ||
| 390 | #endif | ||
| 391 | isvalid = strstr(cookiestr, cls->cookie_name); | ||
| 392 | if (isvalid != NULL) { | ||
| 393 | isvalid += strlen(cls->cookie_name) + 1; | ||
| 394 | cookiebuf = ap_pstrdup(r->pool, isvalid); | ||
| 395 | cookieend = strchr(cookiebuf, ';'); | ||
| 396 | if (cookieend != NULL) | ||
| 397 | *cookieend = '\0'; | ||
| 398 | return cookiebuf; | ||
| 399 | } | ||
| 400 | } | ||
| 401 | |||
| 402 | cookiestr = table_get(r->headers_out, "set-cookie"); | ||
| 403 | if (cookiestr != NULL) { | ||
| 404 | #ifdef DEBUG | ||
| 405 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Set-Cookie: [%s]", cookiestr); | ||
| 406 | #endif | ||
| 407 | isvalid = strstr(cookiestr, cls->cookie_name); | ||
| 408 | if (isvalid != NULL) { | ||
| 409 | isvalid += strlen(cls->cookie_name) + 1; | ||
| 410 | cookiebuf = ap_pstrdup(r->pool, isvalid); | ||
| 411 | cookieend = strchr(cookiebuf, ';'); | ||
| 412 | if (cookieend != NULL) | ||
| 413 | *cookieend = '\0'; | ||
| 414 | return cookiebuf; | ||
| 415 | } | ||
| 416 | } | ||
| 417 | } | ||
| 418 | |||
| 419 | return "-"; | ||
| 420 | } | ||
| 421 | |||
| 422 | static const char *extract_specific_cookie(request_rec *r, char *a) | ||
| 423 | { | ||
| 424 | const char *cookiestr; | ||
| 425 | char *cookieend; | ||
| 426 | char *isvalid; | ||
| 427 | char *cookiebuf; | ||
| 428 | |||
| 429 | if (a != NULL) { | ||
| 430 | #ifdef DEBUG | ||
| 431 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"watching for cookie '%s'", a); | ||
| 432 | #endif | ||
| 433 | |||
| 434 | /* Fetch out the cookie header */ | ||
| 435 | cookiestr = (char *)table_get(r->headers_in, "cookie2"); | ||
| 436 | if (cookiestr != NULL) { | ||
| 437 | #ifdef DEBUG | ||
| 438 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie2: [%s]", cookiestr); | ||
| 439 | #endif | ||
| 440 | /* Does the cookie string contain one with our name? */ | ||
| 441 | isvalid = strstr(cookiestr, a); | ||
| 442 | if (isvalid != NULL) { | ||
| 443 | /* Move past the cookie name and equal sign */ | ||
| 444 | isvalid += strlen(a) + 1; | ||
| 445 | /* Duplicate it into the pool */ | ||
| 446 | cookiebuf = ap_pstrdup(r->pool, isvalid); | ||
| 447 | /* Segregate just this cookie out of the string | ||
| 448 | * with a terminating nul at the first semicolon */ | ||
| 449 | cookieend = strchr(cookiebuf, ';'); | ||
| 450 | if (cookieend != NULL) | ||
| 451 | *cookieend = '\0'; | ||
| 452 | return cookiebuf; | ||
| 453 | } | ||
| 454 | } | ||
| 455 | |||
| 456 | cookiestr = (char *)table_get(r->headers_in, "cookie"); | ||
| 457 | if (cookiestr != NULL) { | ||
| 458 | #ifdef DEBUG | ||
| 459 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Cookie: [%s]", cookiestr); | ||
| 460 | #endif | ||
| 461 | isvalid = strstr(cookiestr, a); | ||
| 462 | if (isvalid != NULL) { | ||
| 463 | isvalid += strlen(a) + 1; | ||
| 464 | cookiebuf = ap_pstrdup(r->pool, isvalid); | ||
| 465 | cookieend = strchr(cookiebuf, ';'); | ||
| 466 | if (cookieend != NULL) | ||
| 467 | *cookieend = '\0'; | ||
| 468 | return cookiebuf; | ||
| 469 | } | ||
| 470 | } | ||
| 471 | |||
| 472 | cookiestr = table_get(r->headers_out, "set-cookie"); | ||
| 473 | if (cookiestr != NULL) { | ||
| 474 | #ifdef DEBUG | ||
| 475 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"Set-Cookie: [%s]", cookiestr); | ||
| 476 | #endif | ||
| 477 | isvalid = strstr(cookiestr, a); | ||
| 478 | if (isvalid != NULL) { | ||
| 479 | isvalid += strlen(a) + 1; | ||
| 480 | cookiebuf = ap_pstrdup(r->pool, isvalid); | ||
| 481 | cookieend = strchr(cookiebuf, ';'); | ||
| 482 | if (cookieend != NULL) | ||
| 483 | *cookieend = '\0'; | ||
| 484 | return cookiebuf; | ||
| 485 | } | ||
| 486 | } | ||
| 487 | } | ||
| 488 | |||
| 489 | return "-"; | ||
| 490 | } | ||
| 491 | |||
| 492 | |||
| 493 | static const char *extract_request_timestamp(request_rec *r, char *a) | ||
| 494 | { | ||
| 495 | char tstr[32]; | ||
| 496 | |||
| 497 | ap_snprintf(tstr, 32, "%ld", time(NULL)); | ||
| 498 | return pstrdup(r->pool, tstr); | ||
| 499 | } | ||
| 500 | |||
| 501 | /* | ||
| 502 | static const char *extract_note(request_rec *r, char *a) | ||
| 503 | { | ||
| 504 | return ap_table_get(r->notes, a); | ||
| 505 | |||
| 506 | } | ||
| 507 | */ | ||
| 508 | |||
| 509 | static const char *extract_env_var(request_rec *r, char *a) | ||
| 510 | { | ||
| 511 | return ap_table_get(r->subprocess_env, a); | ||
| 512 | } | ||
| 513 | |||
| 514 | static const char *extract_unique_id(request_rec *r, char *a) | ||
| 515 | { | ||
| 516 | const char *tempid; | ||
| 517 | |||
| 518 | tempid = ap_table_get(r->subprocess_env, "UNIQUE_ID"); | ||
| 519 | if (!tempid) | ||
| 520 | return "-"; | ||
| 521 | else | ||
| 522 | return tempid; | ||
| 523 | } | ||
| 524 | |||
| 525 | /* End declarations of various extract_ functions */ | ||
| 526 | |||
| 527 | |||
| 528 | |||
| 529 | struct log_sql_item_list { | ||
| 530 | char ch; /* its letter code */ | ||
| 531 | item_key_func func; /* its extraction function */ | ||
| 532 | const char *sql_field_name; /* its column in SQL */ | ||
| 533 | int want_orig_default; /* if it requires the original request prior to internal redirection */ | ||
| 534 | int string_contents; /* if it returns a string */ | ||
| 535 | } log_sql_item_keys[] = { | ||
| 536 | |||
| 537 | { 'A', extract_agent, "agent", 1, 1 }, | ||
| 538 | { 'a', extract_request_args, "request_args", 1, 1 }, | ||
| 539 | { 'b', extract_bytes_sent, "bytes_sent", 0, 0 }, | ||
| 540 | { 'c', extract_cookie, "cookie", 0, 1 }, | ||
| 541 | { 'e', extract_env_var, "env_var", 0, 1 }, | ||
| 542 | { 'f', extract_request_file, "request_file", 0, 1 }, | ||
| 543 | { 'H', extract_request_protocol, "request_protocol", 0, 1 }, | ||
| 544 | { 'h', extract_remote_host, "remote_host", 0, 1 }, | ||
| 545 | { 'I', extract_unique_id, "id", 0, 1 }, | ||
| 546 | { 'l', extract_remote_logname, "remote_logname", 0, 1 }, | ||
| 547 | { 'm', extract_request_method, "request_method", 0, 1 }, | ||
| 548 | { 'M', extract_machine_id, "machine_id", 0, 1 }, | ||
| 549 | { 'P', extract_child_pid, "child_pid", 0, 0 }, | ||
| 550 | { 'p', extract_server_port, "server_port", 0, 0 }, | ||
| 551 | { 'R', extract_referer, "referer", 1, 1 }, | ||
| 552 | { 'r', extract_request_line, "request_line", 1, 1 }, | ||
| 553 | { 'S', extract_request_timestamp, "time_stamp", 0, 0 }, | ||
| 554 | { 's', extract_status, "status", 1, 0 }, | ||
| 555 | { 'T', extract_request_duration, "request_duration", 1, 0 }, | ||
| 556 | { 't', extract_request_time, "request_time", 0, 1 }, | ||
| 557 | { 'u', extract_remote_user, "remote_user", 0, 1 }, | ||
| 558 | { 'U', extract_request_uri, "request_uri", 1, 1 }, | ||
| 559 | { 'v', extract_virtual_host, "virtual_host", 0, 1 }, | ||
| 560 | #ifdef WANT_SSL_LOGGING | ||
| 561 | { 'q', extract_ssl_keysize, "ssl_keysize", 0, 1 }, | ||
| 562 | { 'Q', extract_ssl_maxkeysize, "ssl_maxkeysize", 0, 1 }, | ||
| 563 | { 'z', extract_ssl_cipher, "ssl_cipher", 0, 1 }, | ||
| 564 | #endif | ||
| 565 | {'\0'} | ||
| 566 | }; | ||
| 567 | |||
| 568 | |||
| 569 | /* Routine to escape the 'dangerous' characters that would otherwise | ||
| 570 | * corrupt the INSERT string: ', \, and " | ||
| 571 | */ | ||
| 572 | const char *escape_query(const char *from_str, pool *p) | ||
| 573 | { | ||
| 574 | if (!from_str) | ||
| 575 | return NULL; | ||
| 576 | else { | ||
| 577 | char *to_str; | ||
| 578 | unsigned long length = strlen(from_str); | ||
| 579 | unsigned long retval; | ||
| 580 | |||
| 581 | /* Pre-allocate a new string that could hold twice the original, which would only | ||
| 582 | * happen if the whole original string was 'dangerous' characters. | ||
| 583 | */ | ||
| 584 | to_str = (char *) ap_palloc(p, length * 2 + 1); | ||
| 585 | if (!to_str) { | ||
| 586 | return from_str; | ||
| 587 | } | ||
| 588 | |||
| 589 | if (!logsql_server_p) { | ||
| 590 | /* Well, I would have liked to use the current database charset. mysql is | ||
| 591 | * unavailable, however, so I fall back to the slightly less respectful | ||
| 592 | * mysql_escape_string() function that uses the default charset. | ||
| 593 | */ | ||
| 594 | retval = mysql_escape_string(to_str, from_str, length); | ||
| 595 | } else { | ||
| 596 | /* MySQL is available, so I'll go ahead and respect the current charset when | ||
| 597 | * I perform the escape. | ||
| 598 | */ | ||
| 599 | retval = mysql_real_escape_string(logsql_server_p, to_str, from_str, length); | ||
| 600 | } | ||
| 601 | |||
| 602 | if (retval) | ||
| 603 | return to_str; | ||
| 604 | else | ||
| 605 | return from_str; | ||
| 606 | } | ||
| 607 | } | ||
| 608 | |||
| 609 | int open_logdb_link(server_rec* s) | ||
| 610 | { | ||
| 611 | /* Returns: | ||
| 612 | 3 if preserve forced | ||
| 613 | 2 if already connected | ||
| 614 | 1 if successful | ||
| 615 | 0 if unsuccessful | ||
| 616 | */ | ||
| 617 | |||
| 618 | if (logsql_forcepreserve) | ||
| 619 | return 3; | ||
| 620 | |||
| 621 | if (logsql_server_p) | ||
| 622 | return 2; | ||
| 623 | |||
| 624 | if ((logsql_dbname) && (logsql_dbhost) && (logsql_dbuser) && (logsql_dbpwd)) { | ||
| 625 | mysql_init(&logsql_server); | ||
| 626 | logsql_server_p = mysql_real_connect(&logsql_server, logsql_dbhost, logsql_dbuser, logsql_dbpwd, logsql_dbname, logsql_tcpport, logsql_socketfile, 0); | ||
| 627 | |||
| 628 | if (logsql_server_p) { | ||
| 629 | #ifdef DEBUG | ||
| 630 | ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", | ||
| 631 | logsql_dbhost, logsql_tcpport, logsql_dbname, logsql_dbuser, logsql_socketfile); | ||
| 632 | #endif | ||
| 633 | return 1; | ||
| 634 | } else { | ||
| 635 | #ifdef DEBUG | ||
| 636 | ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"mod_log_sql: database connection error: %s",MYSQL_ERROR(&logsql_server)); | ||
| 637 | ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"HOST: '%s' PORT: '%d' DB: '%s' USER: '%s' SOCKET: '%s'", | ||
| 638 | logsql_dbhost, logsql_tcpport, logsql_dbname, logsql_dbuser, logsql_socketfile); | ||
| 639 | #endif | ||
| 640 | return 0; | ||
| 641 | } | ||
| 642 | } else { | ||
| 643 | ap_log_error(APLOG_MARK,ERRLEVEL,s,"mod_log_sql: insufficient configuration info to establish database link"); | ||
| 644 | return 0; | ||
| 645 | } | ||
| 646 | } | ||
| 647 | |||
| 648 | const char *extract_table(void *data, const char *key, const char *val) | ||
| 649 | { | ||
| 650 | request_rec *r = (request_rec *)data; | ||
| 651 | |||
| 652 | return ap_pstrcat(r->pool, key, " = ", val, " ", NULL); | ||
| 653 | } | ||
| 654 | |||
| 655 | void preserve_entry(request_rec *r, const char *query) | ||
| 656 | { | ||
| 657 | FILE *fp; | ||
| 658 | logsql_state *cls = get_module_config(r->server->module_config, &sql_log_module); | ||
| 659 | |||
| 660 | fp = pfopen(r->pool, cls->preserve_file, "a"); | ||
| 661 | if (fp == NULL) | ||
| 662 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: attempted append of local preserve file but failed."); | ||
| 663 | else { | ||
| 664 | fprintf(fp,"%s;\n", query); | ||
| 665 | pfclose(r->pool, fp); | ||
| 666 | #ifdef DEBUG | ||
| 667 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_sql: entry preserved in %s", cls->preserve_file); | ||
| 668 | #endif | ||
| 669 | } | ||
| 670 | } | ||
| 671 | |||
| 672 | |||
| 673 | /*-----------------------------------------------------*/ | ||
| 674 | /* safe_sql_query: perform a database query with */ | ||
| 675 | /* a degree of safety and error checking. */ | ||
| 676 | /* */ | ||
| 677 | /* Parms: request record, SQL insert statement */ | ||
| 678 | /* Returns: 0 (OK) on success */ | ||
| 679 | /* 1 if have no log handle */ | ||
| 680 | /* 2 if insert delayed failed (kluge) */ | ||
| 681 | /* the actual MySQL return code on error */ | ||
| 682 | /*-----------------------------------------------------*/ | ||
| 683 | unsigned int safe_sql_query(request_rec *r, const char *query) | ||
| 684 | { | ||
| 685 | int retval; | ||
| 686 | struct timespec delay, remainder; | ||
| 687 | int ret; | ||
| 688 | void (*handler) (int); | ||
| 689 | logsql_state *cls; | ||
| 690 | unsigned int real_error; | ||
| 691 | #ifdef WANT_DELAYED_MYSQL_INSERT | ||
| 692 | char *real_error_str; | ||
| 693 | #endif | ||
| 694 | |||
| 695 | /* A failed mysql_query() may send a SIGPIPE, so we ignore that signal momentarily. */ | ||
| 696 | handler = signal(SIGPIPE, SIG_IGN); | ||
| 697 | |||
| 698 | /* First attempt for the query */ | ||
| 699 | if (!logsql_server_p) { | ||
| 700 | signal(SIGPIPE, handler); | ||
| 701 | return 1; | ||
| 702 | } else if (!(retval = mysql_query(logsql_server_p, query))) { | ||
| 703 | signal(SIGPIPE, handler); | ||
| 704 | return 0; | ||
| 705 | } | ||
| 706 | |||
| 707 | /* If we ran the query and it returned an error, try to be robust. | ||
| 708 | * (After all, the module thought it had a valid mysql_log connection but the query | ||
| 709 | * could have failed for a number of reasons, so we have to be extra-safe and check.) */ | ||
| 710 | #ifdef WANT_DELAYED_MYSQL_INSERT | ||
| 711 | real_error_str = MYSQL_ERROR(logsql_server_p); | ||
| 712 | #else | ||
| 713 | real_error = mysql_errno(logsql_server_p); | ||
| 714 | #endif | ||
| 715 | |||
| 716 | /* Check to see if the error is "nonexistent table" */ | ||
| 717 | #ifdef WANT_DELAYED_MYSQL_INSERT | ||
| 718 | if ((strstr(real_error_str, "Table")) && (strstr(real_error_str,"doesn't exist"))) { | ||
| 719 | #else | ||
| 720 | if (real_error == ER_NO_SUCH_TABLE) { | ||
| 721 | #endif | ||
| 722 | if (logsql_createtables) { | ||
| 723 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: table doesn't exist...creating now"); | ||
| 724 | cls = get_module_config(r->server->module_config, &sql_log_module); | ||
| 725 | if (safe_create_tables(cls, r)) { | ||
| 726 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: child attempted but failed to create one or more tables for %s, preserving query", ap_get_server_name(r)); | ||
| 727 | preserve_entry(r, query); | ||
| 728 | retval = mysql_errno(logsql_server_p); | ||
| 729 | } else { | ||
| 730 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: tables successfully created - retrying query"); | ||
| 731 | if (mysql_query(logsql_server_p, query)) { | ||
| 732 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: giving up, preserving query"); | ||
| 733 | preserve_entry(r, query); | ||
| 734 | retval = mysql_errno(logsql_server_p); | ||
| 735 | } else | ||
| 736 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: query successful after table creation"); | ||
| 737 | retval = 0; | ||
| 738 | } | ||
| 739 | } else { | ||
| 740 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql, table doesn't exist, creation denied by configuration, preserving query"); | ||
| 741 | preserve_entry(r, query); | ||
| 742 | retval = ER_NO_SUCH_TABLE; | ||
| 743 | } | ||
| 744 | /* Restore SIGPIPE to its original handler function */ | ||
| 745 | signal(SIGPIPE, handler); | ||
| 746 | return retval; | ||
| 747 | } | ||
| 748 | |||
| 749 | /* Handle all other types of errors */ | ||
| 750 | |||
| 751 | cls = get_module_config(r->server->module_config, &sql_log_module); | ||
| 752 | |||
| 753 | /* Something went wrong, so start by trying to restart the db link. */ | ||
| 754 | #ifdef WANT_DELAYED_MYSQL_INSERT | ||
| 755 | real_error = 2; | ||
| 756 | #else | ||
| 757 | real_error = mysql_errno(logsql_server_p); | ||
| 758 | #endif | ||
| 759 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: first attempt failed, API said: error %d, \"%s\"", real_error, MYSQL_ERROR(logsql_server_p)); | ||
| 760 | mysql_close(logsql_server_p); | ||
| 761 | logsql_server_p = NULL; | ||
| 762 | open_logdb_link(r->server); | ||
| 763 | |||
| 764 | if (logsql_server_p == NULL) { /* still unable to link */ | ||
| 765 | signal(SIGPIPE, handler); | ||
| 766 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: reconnect failed, unable to reach database. SQL logging stopped until child regains a db connection."); | ||
| 767 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: log entries are being preserved in %s", cls->preserve_file); | ||
| 768 | return 1; | ||
| 769 | } else | ||
| 770 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: db reconnect successful"); | ||
| 771 | |||
| 772 | /* First sleep for a tiny amount of time. */ | ||
| 773 | delay.tv_sec = 0; | ||
| 774 | delay.tv_nsec = 250000000; /* max is 999999999 (nine nines) */ | ||
| 775 | ret = nanosleep(&delay, &remainder); | ||
| 776 | if (ret && errno != EINTR) | ||
| 777 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: nanosleep unsuccessful"); | ||
| 778 | |||
| 779 | /* Then make our second attempt */ | ||
| 780 | retval = mysql_query(logsql_server_p,query); | ||
| 781 | |||
| 782 | /* If this one also failed, log that and append to our local offline file */ | ||
| 783 | if (retval) { | ||
| 784 | #ifdef WANT_DELAYED_MYSQL_INSERT | ||
| 785 | real_error = 2; | ||
| 786 | #else | ||
| 787 | real_error = mysql_errno(logsql_server_p); | ||
| 788 | #endif | ||
| 789 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: second attempt failed, API said: error %d, \"%s\" -- preserving", real_error, MYSQL_ERROR(logsql_server_p)); | ||
| 790 | preserve_entry(r, query); | ||
| 791 | retval = real_error; | ||
| 792 | } else | ||
| 793 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: second attempt successful"); | ||
| 794 | |||
| 795 | /* Restore SIGPIPE to its original handler function */ | ||
| 796 | signal(SIGPIPE, handler); | ||
| 797 | return retval; | ||
| 798 | } | ||
| 799 | |||
| 800 | /*-----------------------------------------------------*/ | ||
| 801 | /* safe_create_tables: create SQL table set for the */ | ||
| 802 | /* virtual server represented by cls. */ | ||
| 803 | /* */ | ||
| 804 | /* Parms: virtserver structure, request record */ | ||
| 805 | /* Returns: 0 on no errors */ | ||
| 806 | /* mysql error code on failure */ | ||
| 807 | /*-----------------------------------------------------*/ | ||
| 808 | int safe_create_tables(logsql_state *cls, request_rec *r) | ||
| 809 | { | ||
| 810 | int retval; | ||
| 811 | unsigned int create_results; | ||
| 812 | char *create_access = NULL; | ||
| 813 | char *create_notes = NULL; | ||
| 814 | char *create_hout = NULL; | ||
| 815 | char *create_hin = NULL; | ||
| 816 | char *create_cookies = NULL; | ||
| 817 | |||
| 818 | char *createprefix = "create table if not exists `"; | ||
| 819 | char *access_suffix = | ||
| 820 | "` (id char(19),\ | ||
| 821 | agent varchar(255),\ | ||
| 822 | bytes_sent int unsigned,\ | ||
| 823 | child_pid smallint unsigned,\ | ||
| 824 | cookie varchar(255),\ | ||
| 825 | machine_id varchar(25),\ | ||
| 826 | request_file varchar(255),\ | ||
| 827 | referer varchar(255),\ | ||
| 828 | remote_host varchar(50),\ | ||
| 829 | remote_logname varchar(50),\ | ||
| 830 | remote_user varchar(50),\ | ||
| 831 | request_duration smallint unsigned,\ | ||
| 832 | request_line varchar(255),\ | ||
| 833 | request_method varchar(10),\ | ||
| 834 | request_protocol varchar(10),\ | ||
| 835 | request_time char(28),\ | ||
| 836 | request_uri varchar(50),\ | ||
| 837 | request_args varchar(255),\ | ||
| 838 | server_port smallint unsigned,\ | ||
| 839 | ssl_cipher varchar(25),\ | ||
| 840 | ssl_keysize smallint unsigned,\ | ||
| 841 | ssl_maxkeysize smallint unsigned,\ | ||
| 842 | status smallint unsigned,\ | ||
| 843 | time_stamp int unsigned,\ | ||
| 844 | virtual_host varchar(50))"; | ||
| 845 | |||
| 846 | char *notes_suffix = | ||
| 847 | "` (id char(19),\ | ||
| 848 | item varchar(80),\ | ||
| 849 | val varchar(80))"; | ||
| 850 | |||
| 851 | char *headers_suffix = | ||
| 852 | "` (id char(19),\ | ||
| 853 | item varchar(80),\ | ||
| 854 | val varchar(80))"; | ||
| 855 | |||
| 856 | char *cookies_suffix = | ||
| 857 | "` (id char(19),\ | ||
| 858 | item varchar(80),\ | ||
| 859 | val varchar(80))"; | ||
| 860 | |||
| 861 | /* Find memory long enough to hold the whole CREATE string + \0 */ | ||
| 862 | create_access = ap_pstrcat(r->pool, createprefix, cls->transfer_table_name, access_suffix, NULL); | ||
| 863 | create_notes = ap_pstrcat(r->pool, createprefix, cls->notes_table_name, notes_suffix, NULL); | ||
| 864 | create_hout = ap_pstrcat(r->pool, createprefix, cls->hout_table_name, headers_suffix, NULL); | ||
| 865 | create_hin = ap_pstrcat(r->pool, createprefix, cls->hin_table_name, headers_suffix, NULL); | ||
| 866 | create_cookies= ap_pstrcat(r->pool, createprefix, cls->cookie_table_name, cookies_suffix, NULL); | ||
| 867 | |||
| 868 | #ifdef DEBUG | ||
| 869 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_sql: create string: %s", create_access); | ||
| 870 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_sql: create string: %s", create_notes); | ||
| 871 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_sql: create string: %s", create_hout); | ||
| 872 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_sql: create string: %s", create_hin); | ||
| 873 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_sql: create string: %s", create_cookies); | ||
| 874 | #endif | ||
| 875 | |||
| 876 | /* Assume that things worked unless told otherwise */ | ||
| 877 | retval = 0; | ||
| 878 | |||
| 879 | if ((create_results = safe_sql_query(r, create_access))) { | ||
| 880 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: failed to create access table"); | ||
| 881 | retval = create_results; | ||
| 882 | } | ||
| 883 | |||
| 884 | if ((create_results = safe_sql_query(r, create_notes))) { | ||
| 885 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: failed to create notes table"); | ||
| 886 | retval = create_results; | ||
| 887 | } | ||
| 888 | |||
| 889 | if ((create_results = safe_sql_query(r, create_hin))) { | ||
| 890 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: failed to create header_out table"); | ||
| 891 | retval = create_results; | ||
| 892 | } | ||
| 893 | |||
| 894 | if ((create_results = safe_sql_query(r, create_hout))) { | ||
| 895 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: failed to create header_in table"); | ||
| 896 | retval = create_results; | ||
| 897 | } | ||
| 898 | |||
| 899 | if ((create_results = safe_sql_query(r, create_cookies))) { | ||
| 900 | ap_log_error(APLOG_MARK,ERRLEVEL,r->server,"mod_log_sql: failed to create cookies table"); | ||
| 901 | retval = create_results; | ||
| 902 | } | ||
| 903 | |||
| 904 | return retval; | ||
| 905 | } | ||
| 906 | |||
| 907 | /* ------------------------------------------------* | ||
| 908 | * Command handlers that are called according * | ||
| 909 | * to the directives found at Apache runtime. * | ||
| 910 | * ------------------------------------------------*/ | ||
| 911 | |||
| 912 | const char *set_log_sql_massvirtual(cmd_parms *parms, void *dummy, int flag) | ||
| 913 | { | ||
| 914 | logsql_massvirtual = ( flag ? 1 : 0); | ||
| 915 | return NULL; | ||
| 916 | } | ||
| 917 | |||
| 918 | const char *set_log_sql_force_preserve(cmd_parms *parms, void *dummy, int flag) | ||
| 919 | { | ||
| 920 | logsql_forcepreserve = ( flag ? 1 : 0); | ||
| 921 | return NULL; | ||
| 922 | } | ||
| 923 | |||
| 924 | const char *set_log_sql_machine_id(cmd_parms *parms, void *dummy, char *arg) | ||
| 925 | { | ||
| 926 | logsql_machid = arg; | ||
| 927 | return NULL; | ||
| 928 | } | ||
| 929 | |||
| 930 | const char *set_log_sql_create(cmd_parms *parms, void *dummy, int flag) | ||
| 931 | { | ||
| 932 | if (logsql_massvirtual) | ||
| 933 | ap_log_error(APLOG_MARK,WARNINGLEVEL,parms->server,"mod_log_sql: do not set LogSQLCreateTables when LogSQLMassVirtualHosting is On. Ignoring."); | ||
| 934 | else | ||
| 935 | logsql_createtables = ( flag ? 1 : 0); | ||
| 936 | return NULL; | ||
| 937 | } | ||
| 938 | |||
| 939 | const char *set_log_sql_db(cmd_parms *parms, void *dummy, char *arg) | ||
| 940 | { | ||
| 941 | logsql_dbname = arg; | ||
| 942 | return NULL; | ||
| 943 | } | ||
| 944 | |||
| 945 | const char *set_log_sql_cookie(cmd_parms *parms, void *dummy, char *arg) | ||
| 946 | { | ||
| 947 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 948 | |||
| 949 | cls->cookie_name = arg; | ||
| 950 | return NULL; | ||
| 951 | } | ||
| 952 | |||
| 953 | const char *set_log_sql_preserve_file(cmd_parms *parms, void *dummy, char *arg) | ||
| 954 | { | ||
| 955 | /* char *pfile; */ | ||
| 956 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 957 | |||
| 958 | /* pfile = ap_pstrcat(parms->pool, "/tmp/", arg, NULL); */ | ||
| 959 | cls->preserve_file = arg; | ||
| 960 | return NULL; | ||
| 961 | } | ||
| 962 | |||
| 963 | const char *set_log_sql_info(cmd_parms *parms, void *dummy, char *host, char *user, char *pwd) | ||
| 964 | { | ||
| 965 | if (*host != '.') { | ||
| 966 | logsql_dbhost = host; | ||
| 967 | } | ||
| 968 | if (*user != '.') { | ||
| 969 | logsql_dbuser = user; | ||
| 970 | } | ||
| 971 | if (*pwd != '.') { | ||
| 972 | logsql_dbpwd = pwd; | ||
| 973 | } | ||
| 974 | return NULL; | ||
| 975 | } | ||
| 976 | |||
| 977 | const char *set_log_sql_transfer_table(cmd_parms *parms, void *dummy, char *arg) | ||
| 978 | { | ||
| 979 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 980 | |||
| 981 | if (logsql_massvirtual != 0) | ||
| 982 | ap_log_error(APLOG_MARK,WARNINGLEVEL,parms->server,"mod_log_sql: do not set LogSQLTransferLogTable when LogSQLMassVirtualHosting is On. Ignoring."); | ||
| 983 | else | ||
| 984 | cls->transfer_table_name = arg; | ||
| 985 | return NULL; | ||
| 986 | } | ||
| 987 | |||
| 988 | const char *set_log_sql_cookie_table(cmd_parms *parms, void *dummy, char *arg) | ||
| 989 | { | ||
| 990 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 991 | |||
| 992 | if (logsql_massvirtual != 0) | ||
| 993 | ap_log_error(APLOG_MARK,WARNINGLEVEL,parms->server,"mod_log_sql: do not set LogSQLCookieLogTable when LogSQLMassVirtualHosting is On. Ignoring."); | ||
| 994 | else | ||
| 995 | cls->cookie_table_name = arg; | ||
| 996 | return NULL; | ||
| 997 | } | ||
| 998 | |||
| 999 | const char *set_log_sql_notes_table(cmd_parms *parms, void *dummy, char *arg) | ||
| 1000 | { | ||
| 1001 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1002 | |||
| 1003 | if (logsql_massvirtual != 0) | ||
| 1004 | ap_log_error(APLOG_MARK,WARNINGLEVEL,parms->server,"mod_log_sql: do not set LogSQLNotesLogTable when LogSQLMassVirtualHosting is On. Ignoring."); | ||
| 1005 | else | ||
| 1006 | cls->notes_table_name = arg; | ||
| 1007 | return NULL; | ||
| 1008 | } | ||
| 1009 | |||
| 1010 | const char *set_log_sql_hin_table(cmd_parms *parms, void *dummy, char *arg) | ||
| 1011 | { | ||
| 1012 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1013 | |||
| 1014 | if (logsql_massvirtual != 0) | ||
| 1015 | ap_log_error(APLOG_MARK,WARNINGLEVEL,parms->server,"mod_log_sql: do not set LogSQLHeadersInLogTable when LogSQLMassVirtualHosting is On. Ignoring."); | ||
| 1016 | else | ||
| 1017 | cls->hin_table_name = arg; | ||
| 1018 | return NULL; | ||
| 1019 | } | ||
| 1020 | |||
| 1021 | const char *set_log_sql_hout_table(cmd_parms *parms, void *dummy, char *arg) | ||
| 1022 | { | ||
| 1023 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1024 | |||
| 1025 | if (logsql_massvirtual != 0) | ||
| 1026 | ap_log_error(APLOG_MARK,WARNINGLEVEL,parms->server,"mod_log_sql: do not set LogSQLHeadersOutLogTable when LogSQLMassVirtualHosting is On. Ignoring."); | ||
| 1027 | else | ||
| 1028 | cls->hout_table_name = arg; | ||
| 1029 | return NULL; | ||
| 1030 | } | ||
| 1031 | |||
| 1032 | const char *set_log_sql_transfer_log_format(cmd_parms *parms, void *dummy, char *arg) | ||
| 1033 | { | ||
| 1034 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1035 | |||
| 1036 | cls->transfer_log_format = arg; | ||
| 1037 | return NULL; | ||
| 1038 | } | ||
| 1039 | |||
| 1040 | const char *set_log_sql_socket_file(cmd_parms *parms, void *dummy, char *arg) | ||
| 1041 | { | ||
| 1042 | logsql_socketfile = arg; | ||
| 1043 | |||
| 1044 | return NULL; | ||
| 1045 | } | ||
| 1046 | |||
| 1047 | const char *set_log_sql_tcp_port(cmd_parms *parms, void *dummy, char *arg) | ||
| 1048 | { | ||
| 1049 | logsql_tcpport = (unsigned int)atoi(arg); | ||
| 1050 | |||
| 1051 | return NULL; | ||
| 1052 | } | ||
| 1053 | |||
| 1054 | const char *add_log_sql_transfer_accept(cmd_parms *parms, void *dummy, char *arg) | ||
| 1055 | { | ||
| 1056 | char **addme; | ||
| 1057 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1058 | |||
| 1059 | addme = push_array(cls->transfer_accept_list); | ||
| 1060 | *addme = pstrdup(cls->transfer_accept_list->pool, arg); | ||
| 1061 | return NULL; | ||
| 1062 | } | ||
| 1063 | |||
| 1064 | const char *add_log_sql_transfer_ignore(cmd_parms *parms, void *dummy, char *arg) | ||
| 1065 | { | ||
| 1066 | char **addme; | ||
| 1067 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1068 | |||
| 1069 | addme = push_array(cls->transfer_ignore_list); | ||
| 1070 | *addme = pstrdup(cls->transfer_ignore_list->pool, arg); | ||
| 1071 | return NULL; | ||
| 1072 | } | ||
| 1073 | |||
| 1074 | const char *add_log_sql_remhost_ignore(cmd_parms *parms, void *dummy, char *arg) | ||
| 1075 | { | ||
| 1076 | char **addme; | ||
| 1077 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1078 | |||
| 1079 | addme = push_array(cls->remhost_ignore_list); | ||
| 1080 | *addme = pstrdup(cls->remhost_ignore_list->pool, arg); | ||
| 1081 | return NULL; | ||
| 1082 | } | ||
| 1083 | |||
| 1084 | const char *add_log_sql_note(cmd_parms *parms, void *dummy, char *arg) | ||
| 1085 | { | ||
| 1086 | char **addme; | ||
| 1087 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1088 | |||
| 1089 | addme = push_array(cls->notes_list); | ||
| 1090 | *addme = pstrdup(cls->notes_list->pool, arg); | ||
| 1091 | return NULL; | ||
| 1092 | } | ||
| 1093 | |||
| 1094 | const char *add_log_sql_hout(cmd_parms *parms, void *dummy, char *arg) | ||
| 1095 | { | ||
| 1096 | char **addme; | ||
| 1097 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1098 | |||
| 1099 | addme = push_array(cls->hout_list); | ||
| 1100 | *addme = pstrdup(cls->hout_list->pool, arg); | ||
| 1101 | return NULL; | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | const char *add_log_sql_hin(cmd_parms *parms, void *dummy, char *arg) | ||
| 1105 | { | ||
| 1106 | char **addme; | ||
| 1107 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1108 | |||
| 1109 | addme = push_array(cls->hin_list); | ||
| 1110 | *addme = pstrdup(cls->hin_list->pool, arg); | ||
| 1111 | return NULL; | ||
| 1112 | } | ||
| 1113 | |||
| 1114 | const char *add_log_sql_cookie(cmd_parms *parms, void *dummy, char *arg) | ||
| 1115 | { | ||
| 1116 | char **addme; | ||
| 1117 | logsql_state *cls = get_module_config(parms->server->module_config, &sql_log_module); | ||
| 1118 | |||
| 1119 | addme = push_array(cls->cookie_list); | ||
| 1120 | *addme = pstrdup(cls->cookie_list->pool, arg); | ||
| 1121 | return NULL; | ||
| 1122 | } | ||
| 1123 | |||
| 1124 | |||
| 1125 | |||
| 1126 | /*------------------------------------------------------------* | ||
| 1127 | * Apache-specific hooks into the module code * | ||
| 1128 | * that are defined in the array 'mysql_lgog_module' (at EOF) * | ||
| 1129 | *------------------------------------------------------------*/ | ||
| 1130 | |||
| 1131 | |||
| 1132 | /* | ||
| 1133 | * This function is called during server initialisation when an heavy-weight | ||
| 1134 | * process (such as a child) is being initialised. As with the | ||
| 1135 | * module-initialisation function, any information that needs to be recorded | ||
| 1136 | * must be in static cells, since there's no configuration record. | ||
| 1137 | * | ||
| 1138 | * There is no return value. | ||
| 1139 | */ | ||
| 1140 | static void log_sql_child_init(server_rec *s, pool *p) | ||
| 1141 | { | ||
| 1142 | int retval; | ||
| 1143 | |||
| 1144 | /* Open a link to the database */ | ||
| 1145 | retval = open_logdb_link(s); | ||
| 1146 | if (!retval) | ||
| 1147 | ap_log_error(APLOG_MARK,ERRLEVEL,s,"mod_log_sql: child spawned but unable to open database link"); | ||
| 1148 | |||
| 1149 | #ifdef DEBUG | ||
| 1150 | if ( (retval == 1) || (retval == 2) ) | ||
| 1151 | ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"mod_log_sql: open_logdb_link successful"); | ||
| 1152 | if (retval == 3) | ||
| 1153 | ap_log_error(APLOG_MARK,DEBUGLEVEL,s,"mod_log_sql: open_logdb_link said that preservation is forced"); | ||
| 1154 | #endif | ||
| 1155 | } | ||
| 1156 | |||
| 1157 | /* | ||
| 1158 | * This function is called when an heavy-weight process (such as a child) is | ||
| 1159 | * being run down or destroyed. As with the child-initialisation function, | ||
| 1160 | * any information that needs to be recorded must be in static cells, since | ||
| 1161 | * there's no configuration record. | ||
| 1162 | * | ||
| 1163 | * There is no return value. | ||
| 1164 | */ | ||
| 1165 | static void log_sql_child_exit(server_rec *s, pool *p) | ||
| 1166 | { | ||
| 1167 | mysql_close(logsql_server_p); | ||
| 1168 | } | ||
| 1169 | |||
| 1170 | |||
| 1171 | /* | ||
| 1172 | void *log_sql_initializer(server_rec *main_server, pool *p) | ||
| 1173 | { | ||
| 1174 | server_rec *s; | ||
| 1175 | |||
| 1176 | logsql_state main_conf = ap_get_module_config(main_server->module_config, &sql_log_module); | ||
| 1177 | |||
| 1178 | for (server_rec *s = main_server; s; s = s->next) { | ||
| 1179 | conf = ap_get_module_config(s->module_config, &sql_log_module); | ||
| 1180 | if (conf->transfer_log_format == NULL && s != main_server) { | ||
| 1181 | *conf = *main_conf; | ||
| 1182 | } | ||
| 1183 | |||
| 1184 | } | ||
| 1185 | */ | ||
| 1186 | |||
| 1187 | /* | ||
| 1188 | * This function gets called to create a per-server configuration | ||
| 1189 | * record. It will always be called for the main server and | ||
| 1190 | * for each virtual server that is established. Each server maintains | ||
| 1191 | * its own state that is separate from the others' states. | ||
| 1192 | * | ||
| 1193 | * The return value is a pointer to the created module-specific | ||
| 1194 | * structure. | ||
| 1195 | */ | ||
| 1196 | void *log_sql_make_state(pool *p, server_rec *s) | ||
| 1197 | { | ||
| 1198 | |||
| 1199 | logsql_state *cls = (logsql_state *) ap_palloc(p, sizeof(logsql_state)); | ||
| 1200 | |||
| 1201 | /* These defaults are overridable in the httpd.conf file. */ | ||
| 1202 | cls->transfer_table_name = NULL; /* No default b/c we want its absence to disable logging */ | ||
| 1203 | cls->transfer_log_format = "AbHhmRSsTUuv"; | ||
| 1204 | cls->notes_table_name = "notes"; | ||
| 1205 | cls->hin_table_name = "headers_in"; | ||
| 1206 | cls->hout_table_name = "headers_out"; | ||
| 1207 | cls->cookie_table_name = "cookies"; | ||
| 1208 | cls->preserve_file = "/tmp/sql-preserve"; | ||
| 1209 | |||
| 1210 | cls->transfer_ignore_list = make_array(p, 1, sizeof(char *)); | ||
| 1211 | cls->transfer_accept_list = make_array(p, 1, sizeof(char *)); | ||
| 1212 | cls->remhost_ignore_list = make_array(p, 1, sizeof(char *)); | ||
| 1213 | cls->notes_list = make_array(p, 1, sizeof(char *)); | ||
| 1214 | cls->hin_list = make_array(p, 1, sizeof(char *)); | ||
| 1215 | cls->hout_list = make_array(p, 1, sizeof(char *)); | ||
| 1216 | cls->cookie_list = make_array(p, 1, sizeof(char *)); | ||
| 1217 | cls->cookie_name = NULL; | ||
| 1218 | |||
| 1219 | return (void *) cls; | ||
| 1220 | } | ||
| 1221 | |||
| 1222 | |||
| 1223 | /* Setup of the available httpd.conf configuration commands. | ||
| 1224 | * Structure: command, function called, NULL, where available, how many arguments, verbose description | ||
| 1225 | */ | ||
| 1226 | command_rec log_sql_cmds[] = { | ||
| 1227 | {"LogSQLTransferLogTable", set_log_sql_transfer_table, NULL, RSRC_CONF, TAKE1, | ||
| 1228 | "The database table that holds the transfer log"} | ||
| 1229 | , | ||
| 1230 | {"LogSQLNotesLogTable", set_log_sql_notes_table, NULL, RSRC_CONF, TAKE1, | ||
| 1231 | "The database table that holds the notes"} | ||
| 1232 | , | ||
| 1233 | {"LogSQLHeadersOutLogTable", set_log_sql_hout_table, NULL, RSRC_CONF, TAKE1, | ||
| 1234 | "The database table that holds the outbound headers"} | ||
| 1235 | , | ||
| 1236 | {"LogSQLHeadersInLogTable", set_log_sql_hin_table, NULL, RSRC_CONF, TAKE1, | ||
| 1237 | "The database table that holds the inbound headers"} | ||
| 1238 | , | ||
| 1239 | {"LogSQLCookieLogTable", set_log_sql_cookie_table, NULL, RSRC_CONF, TAKE1, | ||
| 1240 | "The database table that holds the cookie info"} | ||
| 1241 | , | ||
| 1242 | {"LogSQLTransferLogFormat", set_log_sql_transfer_log_format, NULL, RSRC_CONF, TAKE1, | ||
| 1243 | "Instruct the module what information to log to the database transfer log"} | ||
| 1244 | , | ||
| 1245 | {"LogSQLMachineID", set_log_sql_machine_id, NULL, RSRC_CONF, TAKE1, | ||
| 1246 | "Machine ID that the module will log, useful in web clusters to differentiate machines"} | ||
| 1247 | , | ||
| 1248 | {"LogSQLRequestAccept", add_log_sql_transfer_accept, NULL, RSRC_CONF, ITERATE, | ||
| 1249 | "List of URIs to accept for logging. Accesses that don't match will not be logged"} | ||
| 1250 | , | ||
| 1251 | {"LogSQLRequestIgnore", add_log_sql_transfer_ignore, NULL, RSRC_CONF, ITERATE, | ||
| 1252 | "List of URIs to ignore. Accesses that match will not be logged to database"} | ||
| 1253 | , | ||
| 1254 | {"LogSQLRemhostIgnore", add_log_sql_remhost_ignore, NULL, RSRC_CONF, ITERATE, | ||
| 1255 | "List of remote hosts to ignore. Accesses that match will not be logged to database"} | ||
| 1256 | , | ||
| 1257 | {"LogSQLDatabase", set_log_sql_db, NULL, RSRC_CONF, TAKE1, | ||
| 1258 | "The name of the database database for logging"} | ||
| 1259 | , | ||
| 1260 | {"LogSQLWhichCookie", set_log_sql_cookie, NULL, RSRC_CONF, TAKE1, | ||
| 1261 | "The single cookie that you want logged in the access_log when using the 'c' config directive"} | ||
| 1262 | , | ||
| 1263 | {"LogSQLLoginInfo", set_log_sql_info, NULL, RSRC_CONF, TAKE3, | ||
| 1264 | "The database host, user-id and password for logging"} | ||
| 1265 | , | ||
| 1266 | {"LogSQLCreateTables", set_log_sql_create, NULL, RSRC_CONF, FLAG, | ||
| 1267 | "Turn on module's capability to create its SQL tables on the fly"} | ||
| 1268 | , | ||
| 1269 | {"LogSQLMassVirtualHosting", set_log_sql_massvirtual, NULL, RSRC_CONF, FLAG, | ||
| 1270 | "Activates option(s) useful for ISPs performing mass virutal hosting"} | ||
| 1271 | , | ||
| 1272 | {"LogSQLForcePreserve", set_log_sql_force_preserve, NULL, RSRC_CONF, FLAG, | ||
| 1273 | "Forces logging to preserve file and bypasses database"} | ||
| 1274 | , | ||
| 1275 | {"LogSQLPreserveFile", set_log_sql_preserve_file, NULL, RSRC_CONF, TAKE1, | ||
| 1276 | "Name of the file to use for data preservation during database downtime"} | ||
| 1277 | , | ||
| 1278 | {"LogSQLSocketFile", set_log_sql_socket_file, NULL, RSRC_CONF, TAKE1, | ||
| 1279 | "Name of the file to employ for socket connections to database"} | ||
| 1280 | , | ||
| 1281 | {"LogSQLTCPPort", set_log_sql_tcp_port, NULL, RSRC_CONF, TAKE1, | ||
| 1282 | "Port number to use for TCP connections to database, defaults to 3306 if not set"} | ||
| 1283 | , | ||
| 1284 | {"LogSQLWhichNotes", add_log_sql_note, NULL, RSRC_CONF, ITERATE, | ||
| 1285 | "Notes that you would like to log in a separate table"} | ||
| 1286 | , | ||
| 1287 | {"LogSQLWhichHeadersOut", add_log_sql_hout, NULL, RSRC_CONF, ITERATE, | ||
| 1288 | "Outbound headers that you would like to log in a separate table"} | ||
| 1289 | , | ||
| 1290 | {"LogSQLWhichHeadersIn", add_log_sql_hin, NULL, RSRC_CONF, ITERATE, | ||
| 1291 | "Inbound headers that you would like to log in a separate table"} | ||
| 1292 | , | ||
| 1293 | {"LogSQLWhichCookies", add_log_sql_cookie, NULL, RSRC_CONF, ITERATE, | ||
| 1294 | "The cookie(s) that you would like to log in a separate table"} | ||
| 1295 | , | ||
| 1296 | {NULL} | ||
| 1297 | }; | ||
| 1298 | |||
| 1299 | |||
| 1300 | |||
| 1301 | /* Routine to perform the actual construction and execution of the relevant | ||
| 1302 | * INSERT statements. | ||
| 1303 | */ | ||
| 1304 | int log_sql_transaction(request_rec *orig) | ||
| 1305 | { | ||
| 1306 | char **ptrptr, **ptrptr2; | ||
| 1307 | logsql_state *cls = get_module_config(orig->server->module_config, &sql_log_module); | ||
| 1308 | const char *access_query; | ||
| 1309 | request_rec *r; | ||
| 1310 | |||
| 1311 | /* We handle mass virtual hosting differently. Dynamically determine the name | ||
| 1312 | * of the table from the virtual server's name, and flag it for creation. | ||
| 1313 | */ | ||
| 1314 | if (logsql_massvirtual) { | ||
| 1315 | char *access_base = "access_"; | ||
| 1316 | char *notes_base = "notes_"; | ||
| 1317 | char *hout_base = "headout_"; | ||
| 1318 | char *hin_base = "headin_"; | ||
| 1319 | char *cookie_base = "cookies_"; | ||
| 1320 | char *a_tablename; | ||
| 1321 | char *n_tablename; | ||
| 1322 | char *i_tablename; | ||
| 1323 | char *o_tablename; | ||
| 1324 | char *c_tablename; | ||
| 1325 | unsigned int i; | ||
| 1326 | |||
| 1327 | /* Find memory long enough to hold the table name + \0. */ | ||
| 1328 | a_tablename = ap_pstrcat(orig->pool, access_base, ap_get_server_name(orig), NULL); | ||
| 1329 | n_tablename = ap_pstrcat(orig->pool, notes_base, ap_get_server_name(orig), NULL); | ||
| 1330 | i_tablename = ap_pstrcat(orig->pool, hin_base, ap_get_server_name(orig), NULL); | ||
| 1331 | o_tablename = ap_pstrcat(orig->pool, hout_base, ap_get_server_name(orig), NULL); | ||
| 1332 | c_tablename = ap_pstrcat(orig->pool, cookie_base, ap_get_server_name(orig), NULL); | ||
| 1333 | |||
| 1334 | /* Transform any dots to underscores */ | ||
| 1335 | for (i = 0; i < strlen(a_tablename); i++) { | ||
| 1336 | if (a_tablename[i] == '.') | ||
| 1337 | a_tablename[i] = '_'; | ||
| 1338 | } | ||
| 1339 | for (i = 0; i < strlen(n_tablename); i++) { | ||
| 1340 | if (n_tablename[i] == '.') | ||
| 1341 | n_tablename[i] = '_'; | ||
| 1342 | } | ||
| 1343 | for (i = 0; i < strlen(i_tablename); i++) { | ||
| 1344 | if (i_tablename[i] == '.') | ||
| 1345 | i_tablename[i] = '_'; | ||
| 1346 | } | ||
| 1347 | for (i = 0; i < strlen(o_tablename); i++) { | ||
| 1348 | if (o_tablename[i] == '.') | ||
| 1349 | o_tablename[i] = '_'; | ||
| 1350 | } | ||
| 1351 | for (i = 0; i < strlen(c_tablename); i++) { | ||
| 1352 | if (c_tablename[i] == '.') | ||
| 1353 | c_tablename[i] = '_'; | ||
| 1354 | } | ||
| 1355 | |||
| 1356 | /* Tell this virtual server its transfer table name, and | ||
| 1357 | * turn on create_tables, which is implied by massvirtual. | ||
| 1358 | */ | ||
| 1359 | cls->transfer_table_name = a_tablename; | ||
| 1360 | cls->notes_table_name = n_tablename; | ||
| 1361 | cls->hout_table_name = o_tablename; | ||
| 1362 | cls->hin_table_name = i_tablename; | ||
| 1363 | cls->cookie_table_name = c_tablename; | ||
| 1364 | logsql_createtables = 1; | ||
| 1365 | } | ||
| 1366 | |||
| 1367 | /* Do we have enough info to log? */ | ||
| 1368 | if (!cls->transfer_table_name) { | ||
| 1369 | return DECLINED; | ||
| 1370 | } else { | ||
| 1371 | const char *thehost; | ||
| 1372 | const char *theitem; | ||
| 1373 | char *fields = "", *values = ""; | ||
| 1374 | char *itemsets = ""; | ||
| 1375 | char *note_query = NULL; | ||
| 1376 | char *hin_query = NULL; | ||
| 1377 | char *hout_query = NULL; | ||
| 1378 | char *cookie_query = NULL; | ||
| 1379 | const char *unique_id; | ||
| 1380 | const char *formatted_item; | ||
| 1381 | int i, j, length; | ||
| 1382 | int proceed; | ||
| 1383 | |||
| 1384 | for (r = orig; r->next; r = r->next) { | ||
| 1385 | continue; | ||
| 1386 | } | ||
| 1387 | |||
| 1388 | /* The following is a stolen upsetting mess of pointers, I'm sorry. | ||
| 1389 | * Anyone with the motiviation and/or the time should feel free | ||
| 1390 | * to make this cleaner. :) */ | ||
| 1391 | ptrptr2 = (char **) (cls->transfer_accept_list->elts + (cls->transfer_accept_list->nelts * cls->transfer_accept_list->elt_size)); | ||
| 1392 | |||
| 1393 | /* Go through each element of the accept list and compare it to the | ||
| 1394 | * request_uri. If we don't get a match, return without logging */ | ||
| 1395 | if ((r->uri) && (cls->transfer_accept_list->nelts)) { | ||
| 1396 | proceed = 0; | ||
| 1397 | for (ptrptr = (char **) cls->transfer_accept_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_accept_list->elt_size)) | ||
| 1398 | if (strstr(r->uri, *ptrptr)) { | ||
| 1399 | proceed = 1; | ||
| 1400 | break; | ||
| 1401 | } | ||
| 1402 | if (!proceed) | ||
| 1403 | return OK; | ||
| 1404 | } | ||
| 1405 | |||
| 1406 | /* Go through each element of the ignore list and compare it to the | ||
| 1407 | * request_uri. If we get a match, return without logging */ | ||
| 1408 | ptrptr2 = (char **) (cls->transfer_ignore_list->elts + (cls->transfer_ignore_list->nelts * cls->transfer_ignore_list->elt_size)); | ||
| 1409 | if (r->uri) { | ||
| 1410 | for (ptrptr = (char **) cls->transfer_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->transfer_ignore_list->elt_size)) | ||
| 1411 | if (strstr(r->uri, *ptrptr)) { | ||
| 1412 | return OK; | ||
| 1413 | } | ||
| 1414 | } | ||
| 1415 | |||
| 1416 | /* Go through each element of the ignore list and compare it to the | ||
| 1417 | * remote host. If we get a match, return without logging */ | ||
| 1418 | ptrptr2 = (char **) (cls->remhost_ignore_list->elts + (cls->remhost_ignore_list->nelts * cls->remhost_ignore_list->elt_size)); | ||
| 1419 | thehost = get_remote_host(r->connection, r->per_dir_config, REMOTE_NAME); | ||
| 1420 | if (thehost) { | ||
| 1421 | for (ptrptr = (char **) cls->remhost_ignore_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->remhost_ignore_list->elt_size)) | ||
| 1422 | if (strstr(thehost, *ptrptr)) { | ||
| 1423 | return OK; | ||
| 1424 | } | ||
| 1425 | } | ||
| 1426 | |||
| 1427 | length = strlen(cls->transfer_log_format); | ||
| 1428 | |||
| 1429 | /* Iterate through the format characters and set up the INSERT string according to | ||
| 1430 | * what the user has configured. */ | ||
| 1431 | for (i = 0; i < length; i++) { | ||
| 1432 | j = 0; | ||
| 1433 | |||
| 1434 | while (log_sql_item_keys[j].ch) { | ||
| 1435 | |||
| 1436 | if (log_sql_item_keys[j].ch == cls->transfer_log_format[i]) { | ||
| 1437 | /* Yes, this key is one of the configured keys. | ||
| 1438 | * Call the key's function and put the returned value into 'formatted_item' */ | ||
| 1439 | formatted_item = log_sql_item_keys[j].func(log_sql_item_keys[j].want_orig_default ? orig : r, ""); | ||
| 1440 | |||
| 1441 | /* Massage 'formatted_item' for proper SQL eligibility... */ | ||
| 1442 | if (!formatted_item) { | ||
| 1443 | formatted_item = ""; | ||
| 1444 | } else if (formatted_item[0] == '-' && formatted_item[1] == '\0' && !log_sql_item_keys[j].string_contents) { | ||
| 1445 | /* If apache tried to log a '-' character for a numeric field, convert that to a zero | ||
| 1446 | * because the database expects a numeral and will reject the '-' character. */ | ||
| 1447 | formatted_item = "0"; | ||
| 1448 | } | ||
| 1449 | |||
| 1450 | /* Append the fieldname and value-to-insert to the appropriate strings, quoting stringvals with ' as appropriate */ | ||
| 1451 | fields = pstrcat(r->pool, fields, (i > 0 ? "," : ""), | ||
| 1452 | log_sql_item_keys[j].sql_field_name, NULL); | ||
| 1453 | |||
| 1454 | values = pstrcat(r->pool, values, (i > 0 ? "," : ""), | ||
| 1455 | (log_sql_item_keys[j].string_contents ? "'" : ""), | ||
| 1456 | escape_query(formatted_item, r->pool), | ||
| 1457 | (log_sql_item_keys[j].string_contents ? "'" : ""), NULL); | ||
| 1458 | break; | ||
| 1459 | } | ||
| 1460 | j++; | ||
| 1461 | |||
| 1462 | } | ||
| 1463 | } | ||
| 1464 | |||
| 1465 | /* Work through the list of notes defined by LogSQLWhichNotes */ | ||
| 1466 | i = 0; | ||
| 1467 | unique_id = extract_unique_id(r, ""); | ||
| 1468 | |||
| 1469 | ptrptr2 = (char **) (cls->notes_list->elts + (cls->notes_list->nelts * cls->notes_list->elt_size)); | ||
| 1470 | for (ptrptr = (char **) cls->notes_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->notes_list->elt_size)) { | ||
| 1471 | /* If the specified note (*ptrptr) exists for the current request... */ | ||
| 1472 | if ((theitem = ap_table_get(r->notes, *ptrptr))) { | ||
| 1473 | itemsets = ap_pstrcat(r->pool, itemsets, | ||
| 1474 | (i > 0 ? "," : ""), | ||
| 1475 | "('", | ||
| 1476 | unique_id, | ||
| 1477 | "','", | ||
| 1478 | escape_query(*ptrptr, r->pool), | ||
| 1479 | "','", | ||
| 1480 | escape_query(theitem, r->pool), | ||
| 1481 | "')", | ||
| 1482 | NULL); | ||
| 1483 | i++; | ||
| 1484 | } | ||
| 1485 | } | ||
| 1486 | if ( itemsets != "" ) { | ||
| 1487 | note_query = ap_pstrcat(r->pool, logsql_insertclause, "`", cls->notes_table_name, "` (id, item, val) values ", itemsets, NULL); | ||
| 1488 | #ifdef DEBUG | ||
| 1489 | ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"mod_log_sql: note string: %s", note_query); | ||
| 1490 | #endif | ||
| 1491 | } | ||
| 1492 | |||
| 1493 | /* Work through the list of headers-out defined by LogSQLWhichHeadersOut*/ | ||
| 1494 | i = 0; | ||
| 1495 | itemsets = ""; | ||
| 1496 | |||
| 1497 | ptrptr2 = (char **) (cls->hout_list->elts + (cls->hout_list->nelts * cls->hout_list->elt_size)); | ||
| 1498 | for (ptrptr = (char **) cls->hout_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->hout_list->elt_size)) { | ||
| 1499 | /* If the specified header (*ptrptr) exists for the current request... */ | ||
| 1500 | if ((theitem = ap_table_get(r->headers_out, *ptrptr))) { | ||
| 1501 | itemsets = ap_pstrcat(r->pool, itemsets, | ||
| 1502 | (i > 0 ? "," : ""), | ||
| 1503 | "('", | ||
| 1504 | unique_id, | ||
| 1505 | "','", | ||
| 1506 | escape_query(*ptrptr, r->pool), | ||
| 1507 | "','", | ||
| 1508 | escape_query(theitem, r->pool), | ||
| 1509 | "')", | ||
| 1510 | NULL); | ||
| 1511 | i++; | ||
| 1512 | } | ||
| 1513 | } | ||
| 1514 | if ( itemsets != "" ) { | ||
| 1515 | hout_query = ap_pstrcat(r->pool, logsql_insertclause, "`", cls->hout_table_name, "` (id, item, val) values ", itemsets, NULL); | ||
| 1516 | #ifdef DEBUG | ||
| 1517 | ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"mod_log_sql: header_out string: %s", hout_query); | ||
| 1518 | #endif | ||
| 1519 | } | ||
| 1520 | |||
| 1521 | |||
| 1522 | /* Work through the list of headers-in defined by LogSQLWhichHeadersIn */ | ||
| 1523 | i = 0; | ||
| 1524 | itemsets = ""; | ||
| 1525 | |||
| 1526 | ptrptr2 = (char **) (cls->hin_list->elts + (cls->hin_list->nelts * cls->hin_list->elt_size)); | ||
| 1527 | for (ptrptr = (char **) cls->hin_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->hin_list->elt_size)) { | ||
| 1528 | /* If the specified header (*ptrptr) exists for the current request... */ | ||
| 1529 | if ((theitem = ap_table_get(r->headers_in, *ptrptr))) { | ||
| 1530 | itemsets = ap_pstrcat(r->pool, itemsets, | ||
| 1531 | (i > 0 ? "," : ""), | ||
| 1532 | "('", | ||
| 1533 | unique_id, | ||
| 1534 | "','", | ||
| 1535 | escape_query(*ptrptr, r->pool), | ||
| 1536 | "','", | ||
| 1537 | escape_query(theitem, r->pool), | ||
| 1538 | "')", | ||
| 1539 | NULL); | ||
| 1540 | i++; | ||
| 1541 | } | ||
| 1542 | } | ||
| 1543 | if ( itemsets != "" ) { | ||
| 1544 | hin_query = ap_pstrcat(r->pool, logsql_insertclause, "`", cls->hin_table_name, "` (id, item, val) values ", itemsets, NULL); | ||
| 1545 | #ifdef DEBUG | ||
| 1546 | ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"mod_log_sql: header_in string: %s", hin_query); | ||
| 1547 | #endif | ||
| 1548 | } | ||
| 1549 | |||
| 1550 | |||
| 1551 | /* Work through the list of cookies defined by LogSQLWhichCookies */ | ||
| 1552 | i = 0; | ||
| 1553 | itemsets = ""; | ||
| 1554 | |||
| 1555 | ptrptr2 = (char **) (cls->cookie_list->elts + (cls->cookie_list->nelts * cls->cookie_list->elt_size)); | ||
| 1556 | for (ptrptr = (char **) cls->cookie_list->elts; ptrptr < ptrptr2; ptrptr = (char **) ((char *) ptrptr + cls->cookie_list->elt_size)) { | ||
| 1557 | /* If the specified cookie (*ptrptr) exists for the current request... */ | ||
| 1558 | if ( strncmp((theitem = extract_specific_cookie(r, *ptrptr)), "-", 1) ) { | ||
| 1559 | itemsets = ap_pstrcat(r->pool, itemsets, | ||
| 1560 | (i > 0 ? "," : ""), | ||
| 1561 | "('", | ||
| 1562 | unique_id, | ||
| 1563 | "','", | ||
| 1564 | escape_query(*ptrptr, r->pool), | ||
| 1565 | "','", | ||
| 1566 | escape_query(theitem, r->pool), | ||
| 1567 | "')", | ||
| 1568 | NULL); | ||
| 1569 | i++; | ||
| 1570 | } | ||
| 1571 | |||
| 1572 | } | ||
| 1573 | if ( itemsets != "" ) { | ||
| 1574 | cookie_query = ap_pstrcat(r->pool, logsql_insertclause, "`", cls->cookie_table_name, "` (id, item, val) values ", itemsets, NULL); | ||
| 1575 | #ifdef DEBUG | ||
| 1576 | ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"mod_log_sql: cookie string: %s", cookie_query); | ||
| 1577 | #endif | ||
| 1578 | } | ||
| 1579 | |||
| 1580 | |||
| 1581 | /* Set up the actual INSERT statement */ | ||
| 1582 | access_query = ap_pstrcat(r->pool, logsql_insertclause, "`", cls->transfer_table_name, "` (", fields, ") values (", values, ")", NULL); | ||
| 1583 | |||
| 1584 | #ifdef DEBUG | ||
| 1585 | ap_log_error(APLOG_MARK,DEBUGLEVEL,r->server,"mod_log_sql: access string: %s", access_query); | ||
| 1586 | #endif | ||
| 1587 | |||
| 1588 | /* If the person activated force-preserve, go ahead and push all the entries | ||
| 1589 | * into the preserve file, then return. | ||
| 1590 | */ | ||
| 1591 | if (logsql_forcepreserve) { | ||
| 1592 | #ifdef DEBUG | ||
| 1593 | ap_log_error(APLOG_MARK,DEBUGLEVEL,orig->server,"mod_log_sql: preservation forced"); | ||
| 1594 | #endif | ||
| 1595 | preserve_entry(orig, access_query); | ||
| 1596 | if ( note_query != NULL ) | ||
| 1597 | preserve_entry(orig, note_query); | ||
| 1598 | if ( hin_query != NULL ) | ||
| 1599 | preserve_entry(orig, hin_query); | ||
| 1600 | if ( hout_query != NULL ) | ||
| 1601 | preserve_entry(orig, hout_query); | ||
| 1602 | if ( cookie_query != NULL ) | ||
| 1603 | preserve_entry(orig, cookie_query); | ||
| 1604 | return OK; | ||
| 1605 | } | ||
| 1606 | |||
| 1607 | /* How's our mysql link integrity? */ | ||
| 1608 | if (logsql_server_p == NULL) { | ||
| 1609 | |||
| 1610 | /* Make a try to establish the link */ | ||
| 1611 | open_logdb_link(r->server); | ||
| 1612 | |||
| 1613 | if (logsql_server_p == NULL) { | ||
| 1614 | /* Unable to re-establish a DB link, so assume that it's really | ||
| 1615 | * gone and send the entry to the preserve file instead. | ||
| 1616 | * This short-circuits safe_sql_query() during a db outage and therefore | ||
| 1617 | * we don't keep logging the db error over and over. | ||
| 1618 | */ | ||
| 1619 | preserve_entry(orig, access_query); | ||
| 1620 | if ( note_query != NULL ) | ||
| 1621 | preserve_entry(orig, note_query); | ||
| 1622 | if ( hin_query != NULL ) | ||
| 1623 | preserve_entry(orig, hin_query); | ||
| 1624 | if ( hout_query != NULL ) | ||
| 1625 | preserve_entry(orig, hout_query); | ||
| 1626 | if ( cookie_query != NULL ) | ||
| 1627 | preserve_entry(orig, cookie_query); | ||
| 1628 | |||
| 1629 | return OK; | ||
| 1630 | } else { | ||
| 1631 | /* Whew, we got the DB link back */ | ||
| 1632 | ap_log_error(APLOG_MARK,NOTICELEVEL,orig->server,"mod_log_sql: child established database connection"); | ||
| 1633 | } | ||
| 1634 | } | ||
| 1635 | |||
| 1636 | |||
| 1637 | /* ---> So as of here we have a non-null value of mysql_log. <--- */ | ||
| 1638 | /* ---> i.e. we have a good MySQL connection. <--- */ | ||
| 1639 | |||
| 1640 | /* Make the access-table insert */ | ||
| 1641 | safe_sql_query(orig, access_query); | ||
| 1642 | |||
| 1643 | /* Log the optional notes, headers, etc. */ | ||
| 1644 | if (note_query) | ||
| 1645 | safe_sql_query(orig, note_query); | ||
| 1646 | |||
| 1647 | if (hout_query) | ||
| 1648 | safe_sql_query(orig, hout_query); | ||
| 1649 | |||
| 1650 | if (hin_query) | ||
| 1651 | safe_sql_query(orig, hin_query); | ||
| 1652 | |||
| 1653 | if (cookie_query) | ||
| 1654 | safe_sql_query(orig, cookie_query); | ||
| 1655 | |||
| 1656 | return OK; | ||
| 1657 | } | ||
| 1658 | } | ||
| 1659 | |||
| 1660 | |||
| 1661 | |||
| 1662 | |||
| 1663 | /* The configuration array that sets up the hooks into the module. */ | ||
| 1664 | module sql_log_module = { | ||
| 1665 | STANDARD_MODULE_STUFF, | ||
| 1666 | NULL, /* module initializer */ | ||
| 1667 | NULL, /* create per-dir config */ | ||
| 1668 | NULL, /* merge per-dir config */ | ||
| 1669 | log_sql_make_state, /* create server config */ | ||
| 1670 | NULL, /* merge server config */ | ||
| 1671 | log_sql_cmds, /* config directive table */ | ||
| 1672 | NULL, /* [9] content handlers */ | ||
| 1673 | NULL, /* [2] URI-to-filename translation */ | ||
| 1674 | NULL, /* [5] check/validate user_id */ | ||
| 1675 | NULL, /* [6] check authorization */ | ||
| 1676 | NULL, /* [4] check access by host */ | ||
| 1677 | NULL, /* [7] MIME type checker/setter */ | ||
| 1678 | NULL, /* [8] fixups */ | ||
| 1679 | log_sql_transaction, /* [10] logger */ | ||
| 1680 | NULL /* [3] header parser */ | ||
| 1681 | #if MODULE_MAGIC_NUMBER >= 19970728 /* 1.3-dev or later support these additionals... */ | ||
| 1682 | ,log_sql_child_init, /* child process initializer */ | ||
| 1683 | log_sql_child_exit, /* process exit/cleanup */ | ||
| 1684 | NULL /* [1] post read-request */ | ||
| 1685 | #endif | ||
| 1686 | |||
| 1687 | }; | ||
