/** * Handle transaction context destroy. * * Handles TS_EVENT_HTTP_TXN_CLOSE (transaction close) close event from the * ATS. * * @param[in,out] ctx Transaction context */ static void tsib_txn_ctx_destroy(tsib_txn_ctx *txndata) { if (txndata == NULL) { return; } ib_tx_t *tx = txndata->tx; tsib_ssn_ctx *ssndata = txndata->ssn; assert(tx != NULL); assert(ssndata != NULL); txndata->tx = NULL; ib_log_debug_tx(tx, "TX DESTROY: conn=>%p tx_count=%zd tx=%p id=%s txn_count=%d", tx->conn, tx->conn->tx_count, tx, tx->id, ssndata->txn_count); tx_finish(tx); ib_lock_lock(ssndata->mutex); ib_tx_destroy(tx); txndata->ssn = NULL; /* Decrement the txn count on the ssn, and destroy ssn if it's closing. * We trust TS not to create more TXNs after signalling SSN close! */ if (ssndata->closing && ssndata->txn_count <= 1) { if (ssndata->iconn) { tx_list_destroy(ssndata->iconn); ib_conn_t *conn = ssndata->iconn; ib_engine_t *ib = conn->ib; ssndata->iconn = NULL; TSDebug("ironbee", "tsib_txn_ctx_destroy: calling ib_state_notify_conn_closed()"); ib_state_notify_conn_closed(ib, conn); TSDebug("ironbee", "CONN DESTROY: conn=%p", conn); ib_conn_destroy(conn); } TSContDataSet(ssndata->contp, NULL); TSContDestroy(ssndata->contp); ib_lock_unlock(ssndata->mutex); ib_lock_destroy_malloc(ssndata->mutex); TSfree(ssndata); } else { --(ssndata->txn_count); ib_lock_unlock(ssndata->mutex); } TSfree(txndata); }
ib_status_t ib_uuid_ascii_to_bin( ib_uuid_t *uuid, const char *str ) { uuid_rc_t uuid_rc; size_t uuid_len = UUID_LEN_BIN; size_t str_len; ib_status_t rc = IB_OK; if (uuid == NULL || str == NULL) { return IB_EINVAL; } str_len = strlen(str); if (str_len != UUID_LEN_STR) { return IB_EINVAL; } assert(str_len == UUID_LEN_STR); rc = ib_lock_lock(&g_uuid_lock); if (rc != IB_OK) { return rc; } uuid_rc = uuid_import(g_ossp_uuid, UUID_FMT_STR, str, str_len); if (uuid_rc == UUID_RC_MEM) { rc = IB_EALLOC; goto finish; } else if (uuid_rc != UUID_RC_OK) { rc = IB_EINVAL; goto finish; } uuid_rc = uuid_export(g_ossp_uuid, UUID_FMT_BIN, (void *)&uuid, &uuid_len ); if (uuid_rc == UUID_RC_MEM) { rc = IB_EALLOC; goto finish; } else if (uuid_rc != UUID_RC_OK || uuid_len != UUID_LEN_BIN) { rc = IB_EOTHER; goto finish; } finish: if (ib_lock_unlock(&g_uuid_lock) != IB_OK) { return IB_EOTHER; } return rc; }
/** * Handle session context destroy. * * Handles TS_EVENT_HTTP_SSN_CLOSE (session close) close event from the * ATS. * * @param[in,out] ctx session context */ static void tsib_ssn_ctx_destroy(tsib_ssn_ctx * ssndata) { if (ssndata == NULL) { return; } /* To avoid the risk of sequencing issues with this coming before TXN_CLOSE, * we just mark the session as closing, but leave actually closing it * for the TXN_CLOSE if there's a TXN */ ib_lock_lock(ssndata->mutex); if (ssndata->txn_count == 0) { /* No outstanding TXN_CLOSE to come. */ if (ssndata->iconn != NULL) { ib_conn_t *conn = ssndata->iconn; ssndata->iconn = NULL; tx_list_destroy(conn); TSDebug("ironbee", "tsib_ssn_ctx_destroy: calling ib_state_notify_conn_closed()"); ib_state_notify_conn_closed(conn->ib, conn); TSDebug("ironbee", "CONN DESTROY: conn=%p", conn); ib_conn_destroy(conn); } /* Store off the continuation pointer */ TSCont contp = ssndata->contp; TSContDataSet(contp, NULL); ssndata->contp = NULL; /* Unlock has to come first 'cos ContDestroy destroys the mutex */ TSContDestroy(contp); ib_lock_unlock(ssndata->mutex); ib_lock_destroy_malloc(ssndata->mutex); TSfree(ssndata); } else { ssndata->closing = 1; ib_lock_unlock(ssndata->mutex); } }
ib_status_t ib_uuid_bin_to_ascii( char *str, const ib_uuid_t *uuid ) { IB_FTRACE_INIT(); uuid_rc_t uuid_rc; size_t uuid_len = UUID_LEN_STR+1; ib_status_t rc = IB_OK; if (uuid == NULL || str == NULL) { IB_FTRACE_RET_STATUS(IB_EINVAL); } rc = ib_lock_init(&g_uuid_lock); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } uuid_rc = uuid_import(g_ossp_uuid, UUID_FMT_BIN, uuid, UUID_LEN_BIN); if (uuid_rc == UUID_RC_MEM) { rc = IB_EALLOC; goto finish; } else if (uuid_rc != UUID_RC_OK) { rc = IB_EINVAL; goto finish; } uuid_rc = uuid_export(g_ossp_uuid, UUID_FMT_STR, (void *)&str, &uuid_len); if (uuid_rc == UUID_RC_MEM) { rc = IB_EALLOC; goto finish; } else if (uuid_rc != UUID_RC_OK || uuid_len != UUID_LEN_STR+1) { rc = IB_EOTHER; goto finish; } finish: if (ib_lock_unlock(&g_uuid_lock) != IB_OK) { IB_FTRACE_RET_STATUS(IB_EOTHER); } IB_FTRACE_RET_STATUS(rc); }
ib_status_t ib_uuid_create_v4(ib_uuid_t *uuid) { uuid_rc_t uuid_rc; size_t uuid_len = UUID_LEN_BIN; ib_status_t rc = IB_OK; rc = ib_lock_lock(&g_uuid_lock); if (rc != IB_OK) { return rc; } uuid_rc = uuid_make(g_ossp_uuid, UUID_MAKE_V4); if (uuid_rc == UUID_RC_MEM) { rc = IB_EALLOC; goto finish; } else if (uuid_rc != UUID_RC_OK) { rc = IB_EOTHER; goto finish; } uuid_rc = uuid_export(g_ossp_uuid, UUID_FMT_BIN, (void *)&uuid, &uuid_len ); if (uuid_rc == UUID_RC_MEM) { rc = IB_EALLOC; goto finish; } else if (uuid_rc != UUID_RC_OK || uuid_len != UUID_LEN_BIN) { rc = IB_EOTHER; goto finish; } finish: if (ib_lock_unlock(&g_uuid_lock) != IB_OK) { return IB_EOTHER; } return rc; }
ib_status_t ib_uuid_create_v4(ib_uuid_t *uuid) { IB_FTRACE_INIT(); uuid_rc_t uuid_rc; size_t uuid_len = UUID_LEN_BIN; ib_status_t rc = IB_OK; rc = ib_lock_init(&g_uuid_lock); if (rc != IB_OK) { IB_FTRACE_RET_STATUS(rc); } uuid_rc = uuid_make(g_ossp_uuid, UUID_MAKE_V4); if (uuid_rc == UUID_RC_MEM) { rc = IB_EALLOC; goto finish; } else if (uuid_rc != UUID_RC_OK) { rc = IB_EOTHER; goto finish; } uuid_rc = uuid_export(g_ossp_uuid, UUID_FMT_BIN, (void *)&uuid, &uuid_len); if (uuid_rc == UUID_RC_MEM) { rc = IB_EALLOC; goto finish; } else if (uuid_rc != UUID_RC_OK || uuid_len != UUID_LEN_BIN) { rc = IB_EOTHER; goto finish; } finish: if (ib_lock_unlock(&g_uuid_lock) != IB_OK) { IB_FTRACE_RET_STATUS(IB_EOTHER); } IB_FTRACE_RET_STATUS(rc); }
///! Close the auditlog and write to the index file. ib_status_t core_audit_close(ib_engine_t *ib, ib_auditlog_t *log) { ib_core_audit_cfg_t *cfg = (ib_core_audit_cfg_t *)log->cfg_data; ib_core_cfg_t *corecfg; ib_status_t ib_rc = IB_OK; int sys_rc; char *line = NULL; size_t len = 0; line = malloc(LOGFORMAT_MAX_LINE_LENGTH + 2); if (line == NULL) { return IB_EALLOC; } /* Retrieve corecfg to get the AuditLogIndexFormat */ ib_rc = ib_core_context_config(log->ctx, &corecfg); if (ib_rc != IB_OK) { ib_log_alert(log->ib, "Error accessing core module: %s", ib_status_to_string(ib_rc)); goto cleanup; } /* Notify all handlers that the given audit log is about to close. */ ib_rc = ib_core_dispatch_auditlog( log->tx, IB_CORE_AUDITLOG_CLOSED, log); if (ib_rc != IB_OK) { ib_log_error(log->ib, "Failed to dispatch auditlog to handlers."); goto cleanup; } /* Close the audit log. */ if (cfg->fp != NULL) { fclose(cfg->fp); // Rename temp to real sys_rc = rename(cfg->temp_path, cfg->full_path); if (sys_rc != 0) { sys_rc = errno; ib_log_error(log->ib, "Error renaming auditlog %s: %s (%d)", cfg->temp_path, strerror(sys_rc), sys_rc); ib_rc = IB_EOTHER; goto cleanup; } cfg->fp = NULL; } /* Write to the index file if using one. */ if ((cfg->index_fp != NULL) && (cfg->parts_written > 0)) { size_t written; ib_rc = ib_lock_lock(log->ctx->auditlog->index_fp_lock); if (ib_rc != IB_OK) { goto cleanup; } ib_rc = core_audit_get_index_line(ib, log, line, LOGFORMAT_MAX_LINE_LENGTH, &len); line[len + 0] = '\n'; line[len + 1] = '\0'; if ( (ib_rc != IB_ETRUNC) && (ib_rc != IB_OK) ) { ib_lock_unlock(log->ctx->auditlog->index_fp_lock); goto cleanup; } written = fwrite(line, len, 1, cfg->index_fp); if (written == 0) { sys_rc = errno; ib_log_error(log->ib, "Error writing to audit log index: %s (%d)", strerror(sys_rc), sys_rc); /// @todo Should retry (a piped logger may have died) fclose(cfg->index_fp); cfg->index_fp = NULL; log->ctx->auditlog->index_fp = cfg->index_fp; ib_lock_unlock(log->ctx->auditlog->index_fp_lock); goto cleanup; } fflush(cfg->index_fp); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); } cleanup: if (line != NULL) { free(line); } return ib_rc; }
ib_status_t core_audit_open_auditindexfile(ib_engine_t *ib, ib_auditlog_t *log, ib_core_audit_cfg_t *cfg, ib_core_cfg_t *corecfg) { char* index_file; size_t index_file_sz; ib_status_t ib_rc; int sys_rc; if (log->ctx->auditlog->index == NULL) { return IB_OK; } /* Lock the auditlog configuration for the context. * We lock up here to ensure that external resources are not * double-opened instead of locking only the assignment to * log->ctx->auditlog->index_fp at the bottom of this block. */ ib_rc = ib_lock_lock(log->ctx->auditlog->index_fp_lock); if (ib_rc != IB_OK) { return ib_rc; } if (log->ctx->auditlog->index[0] == '/') { index_file_sz = strlen(log->ctx->auditlog->index) + 1; index_file = (char *)ib_mm_alloc(cfg->tx->mm, index_file_sz); if (index_file == NULL) { ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EALLOC; } memcpy(index_file, log->ctx->auditlog->index, index_file_sz); } else if (log->ctx->auditlog->index[0] == '|') { /// @todo Probably should skip whitespace??? index_file_sz = strlen(log->ctx->auditlog->index + 1) + 1; index_file = (char *)ib_mm_alloc(cfg->tx->mm, index_file_sz); if (index_file == NULL) { ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EALLOC; } memcpy(index_file, log->ctx->auditlog->index + 1, index_file_sz); } else { ib_rc = ib_util_mkpath(corecfg->auditlog_dir, corecfg->auditlog_dmode); if (ib_rc != IB_OK) { ib_log_error(log->ib, "Failed to create audit log dir: %s", corecfg->auditlog_dir); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return ib_rc; } index_file_sz = strlen(corecfg->auditlog_dir) + strlen(log->ctx->auditlog->index) + 2; index_file = (char *)ib_mm_alloc(cfg->tx->mm, index_file_sz); if (index_file == NULL) { ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EALLOC; } sys_rc = snprintf(index_file, index_file_sz, "%s/%s", corecfg->auditlog_dir, log->ctx->auditlog->index); if ((size_t)sys_rc >= index_file_sz) { ib_log_error(log->ib, "Failed to create audit log index \"%s/%s\":" " name too long", corecfg->auditlog_dir, log->ctx->auditlog->index); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } } if (log->ctx->auditlog->index[0] == '|') { int p[2]; pid_t pipe_pid; /// @todo Handle exit of pipe_pid??? sys_rc = pipe(p); if (sys_rc != 0) { ib_log_error(log->ib, "Error creating piped audit log index: %s (%d)", strerror(errno), errno); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } /* Create a new process for executing the piped command. */ pipe_pid = fork(); if (pipe_pid == 0) { /* Child - piped audit log index process */ char *parg[4]; /// @todo Reset SIGCHLD in child??? /* Setup the filehandles to read from pipe. */ close(3); /// @todo stderr close(p[1]); dup2(p[0], 0); /* Execute piped command. */ parg[0] = (char *)ib_pipe_shell; parg[1] = (char *)"-c"; parg[2] = index_file; parg[3] = NULL; execvp(ib_pipe_shell, (char * const *)parg); /// @todo define shell sys_rc = errno; ib_log_error(log->ib, "Error executing piped audit log index " "\"%s\": %s (%d)", index_file, strerror(sys_rc), sys_rc); exit(1); } else if (pipe_pid == -1) { /* Error - no process created */ sys_rc = errno; ib_log_error(log->ib, "Error creating piped audit log index process: " "%s (%d)", strerror(sys_rc), sys_rc); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } /* Parent - IronBee process */ /* Setup the filehandles to write to the pipe. */ close(p[0]); cfg->index_fp = fdopen(p[1], "w"); if (cfg->index_fp == NULL) { sys_rc = errno; ib_log_error(log->ib, "Error opening piped audit log index: %s (%d)", strerror(sys_rc), sys_rc); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } } else { /// @todo Use corecfg->auditlog_fmode as file mode for new file cfg->index_fp = fopen(index_file, "ab"); if (cfg->index_fp == NULL) { sys_rc = errno; ib_log_error(log->ib, "Error opening audit log index \"%s\": %s (%d)", index_file, strerror(sys_rc), sys_rc); ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_EINVAL; } } log->ctx->auditlog->index_fp = cfg->index_fp; ib_lock_unlock(log->ctx->auditlog->index_fp_lock); return IB_OK; }
/** * Plugin for the IronBee ATS. * * Handles some ATS events. * * @param[in,out] contp Pointer to the continuation * @param[in,out] event Event from ATS * @param[in,out] edata Event data * * @returns status */ int ironbee_plugin(TSCont contp, TSEvent event, void *edata) { ib_status_t rc; TSCont mycont; TSHttpTxn txnp = (TSHttpTxn) edata; TSHttpSsn ssnp = (TSHttpSsn) edata; tsib_txn_ctx *txndata; tsib_ssn_ctx *ssndata; tsib_hdr_outcome status; TSMutex ts_mutex = NULL; TSDebug("ironbee", "Entering ironbee_plugin with %d", event); switch (event) { /* CONNECTION */ case TS_EVENT_HTTP_SSN_START: /* start of connection */ /* But we can't initialize conn stuff here, because there's * no API to get the connection stuff required by ironbee * at this point. So instead, intercept the first TXN * * what we can and must do: create a new contp whose * lifetime is our ssn */ ts_mutex = TSMutexCreate(); mycont = TSContCreate(ironbee_plugin, ts_mutex); TSHttpSsnHookAdd (ssnp, TS_HTTP_TXN_START_HOOK, mycont); ssndata = TSmalloc(sizeof(*ssndata)); memset(ssndata, 0, sizeof(*ssndata)); /* The only failure here is EALLOC, and if that happens * we're ****ed anyway */ rc = ib_lock_create_malloc(&(ssndata->mutex)); assert(rc == IB_OK); ssndata->contp = mycont; ssndata->ts_mutex = ts_mutex; TSContDataSet(mycont, ssndata); TSHttpSsnHookAdd (ssnp, TS_HTTP_SSN_CLOSE_HOOK, mycont); TSHttpSsnReenable (ssnp, TS_EVENT_HTTP_CONTINUE); break; case TS_EVENT_HTTP_TXN_START: { /* start of Request */ /* First req on a connection, we set up conn stuff */ ib_status_t rc; ib_engine_t *ib = NULL; ssndata = TSContDataGet(contp); ib_lock_lock(ssndata->mutex); if (ssndata->iconn == NULL) { rc = tsib_manager_engine_acquire(&ib); if (rc == IB_DECLINED) { /* OK, this means the manager is disabled deliberately, * but otherwise all's well. So this TXN * gets processed without intervention from Ironbee * and is invisble when our SSN_CLOSE hook runs. */ ib_lock_unlock(ssndata->mutex); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); TSDebug("ironbee", "Decline from engine manager"); break; } else if (rc != IB_OK) { TSError("[ironbee] Failed to acquire engine: %s", ib_status_to_string(rc)); goto noib_error; } if (ib != NULL) { rc = ib_conn_create(ib, &ssndata->iconn, contp); if (rc != IB_OK) { TSError("[ironbee] ib_conn_create: %s", ib_status_to_string(rc)); tsib_manager_engine_release(ib); goto noib_error; } /* In the normal case, release the engine when the * connection's memory pool is destroyed */ rc = ib_mm_register_cleanup(ssndata->iconn->mm, cleanup_ib_connection, ib); if (rc != IB_OK) { TSError("[ironbee] ib_mm_register_cleanup: %s", ib_status_to_string(rc)); tsib_manager_engine_release(ib); goto noib_error; } TSDebug("ironbee", "CONN CREATE: conn=%p", ssndata->iconn); ssndata->txnp = txnp; ssndata->txn_count = ssndata->closing = 0; rc = ironbee_conn_init(ssndata); if (rc != IB_OK) { TSError("[ironbee] ironbee_conn_init: %s", ib_status_to_string(rc)); goto noib_error; } TSContDataSet(contp, ssndata); TSDebug("ironbee", "ironbee_plugin: ib_state_notify_conn_opened()"); rc = ib_state_notify_conn_opened(ib, ssndata->iconn); if (rc != IB_OK) { TSError("[ironbee] Failed to notify connection opened: %s", ib_status_to_string(rc)); } } else { /* Use TSError where there's no ib or tx */ TSError("Ironbee: No ironbee engine!"); goto noib_error; } } /* create a txn cont (request ctx) and tx */ txndata = TSmalloc(sizeof(*txndata)); memset(txndata, 0, sizeof(*txndata)); txndata->ssn = ssndata; txndata->txnp = txnp; rc = ib_tx_create(&txndata->tx, ssndata->iconn, txndata); if (rc != IB_OK) { TSError("[ironbee] Failed to create tx: %d", rc); tsib_manager_engine_release(ib); TSfree(txndata); goto noib_error; } ++ssndata->txn_count; ib_lock_unlock(ssndata->mutex); ib_log_debug_tx(txndata->tx, "TX CREATE: conn=%p tx=%p id=%s txn_count=%d", ssndata->iconn, txndata->tx, txndata->tx->id, txndata->ssn->txn_count); mycont = TSContCreate(ironbee_plugin, ssndata->ts_mutex); TSContDataSet(mycont, txndata); TSHttpTxnHookAdd(txnp, TS_HTTP_TXN_CLOSE_HOOK, mycont); /* Hook to process responses */ TSHttpTxnHookAdd(txnp, TS_HTTP_READ_RESPONSE_HDR_HOOK, mycont); /* Hook to process requests */ TSHttpTxnHookAdd(txnp, TS_HTTP_READ_REQUEST_HDR_HOOK, mycont); /* Create continuations for input and output filtering * to give them txn lifetime. */ txndata->in_data_cont = TSTransformCreate(in_data_event, txnp); TSContDataSet(txndata->in_data_cont, txndata); txndata->out_data_cont = TSTransformCreate(out_data_event, txnp); TSContDataSet(txndata->out_data_cont, txndata); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); break; noib_error: ib_lock_unlock(ssndata->mutex); /* NULL txndata signals this to SEND_RESPONSE */ mycont = TSContCreate(ironbee_plugin, ssndata->ts_mutex); TSContDataSet(mycont, NULL); TSError("[ironbee] Internal error initialising for transaction"); TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, mycont); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR); break; } /* HTTP RESPONSE */ case TS_EVENT_HTTP_READ_RESPONSE_HDR: txndata = TSContDataGet(contp); if (txndata->tx == NULL) { TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); break; } /* Feed ironbee the headers if not done already. */ if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_STARTED)) { status = process_hdr(txndata, txnp, &tsib_direction_server_resp); /* OK, if this was an HTTP 100 response, it's not the * response we're interested in. No headers have been * sent yet, and no data will be sent until we've * reached here again with the final response. */ if (status == HDR_HTTP_100) { TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); break; } // FIXME: Need to know if this fails as it (I think) means // that the response did not come from the server and // that ironbee should ignore it. /* I've not seen a fail here. AFAICT if either the origin * isn't responding or we're responding from cache. we * never reach here in the first place. */ } /* If ironbee signalled an error while processing request body data, * this is the first opportunity to divert to an errordoc */ if (HTTP_CODE(txndata->status)) { ib_log_debug_tx(txndata->tx, "HTTP code %d contp=%p", txndata->status, contp); TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR); break; } /* If we're not going to inspect response body data * we can bring forward notification of response-end * so we're in time to respond with an errordoc if Ironbee * wants to block in the response phase. * * This currently fails. However, that appears to be because I * can't unset IB_TX_FINSPECT_RESBODY with InspectionEngineOptions */ if (!ib_flags_all(txndata->tx->flags, IB_TX_FINSPECT_RESBODY)) { if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_STARTED) ) { ib_state_notify_response_started(txndata->tx->ib, txndata->tx, NULL); } if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_FINISHED) ) { ib_state_notify_response_finished(txndata->tx->ib, txndata->tx); } /* Test again for Ironbee telling us to block */ if (HTTP_CODE(txndata->status)) { TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR); break; } } /* Flag that we're too late to divert to an error response */ ib_tx_flags_set(txndata->tx, IB_TX_FCLIENTRES_STARTED); /* Normal execution. Add output filter to inspect response. */ TSHttpTxnHookAdd(txnp, TS_HTTP_RESPONSE_TRANSFORM_HOOK, txndata->out_data_cont); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); break; /* Hook for processing response headers. */ case TS_EVENT_HTTP_SEND_RESPONSE_HDR: txndata = TSContDataGet(contp); if (txndata == NULL) { /* Ironbee is unavailable to help with our response. */ internal_error_response(txnp); /* This contp isn't going through the normal flow. */ TSContDestroy(contp); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); break; } /* If ironbee has sent us into an error response then * we came here in our error path, with nonzero status. */ if (txndata->status != 0) { error_response(txnp, txndata); } /* Feed ironbee the headers if not done already. */ if (!ib_flags_all(txndata->tx->flags, IB_TX_FRES_STARTED)) { if (process_hdr(txndata, txnp, &tsib_direction_client_resp) != HDR_OK) { /* I think this is a shouldn't happen event, and that * if it does we have an ironbee bug or misconfiguration. * Log an error to catch if it happens in practice. */ ib_log_error_tx(txndata->tx, "process_hdr returned error in send_response_hdr event"); } } /* If there is an ironbee-generated response body, notify ironbee. * * NOTE: I do not see anywhere else to put this as the error body is * just a buffer and not delivered via normal IO channels, so * the error body will never get caught by an event. */ if ((txndata->status != 0) && (txndata->err_body != NULL)) { const char *data = txndata->err_body; size_t data_length = txndata->err_body_len; ib_log_debug_tx(txndata->tx, "error_response: calling ib_state_notify_response_body_data() %s:%d", __FILE__, __LINE__); ib_state_notify_response_body_data(txndata->tx->ib, txndata->tx, data, data_length); } TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); break; /* HTTP REQUEST */ case TS_EVENT_HTTP_READ_REQUEST_HDR: /* hook to examine output headers. They're not available yet */ TSHttpTxnHookAdd(txnp, TS_HTTP_PRE_REMAP_HOOK, contp); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); break; /* hook for processing incoming request/headers * The OS_DNS hook is an alternative here. */ case TS_EVENT_HTTP_PRE_REMAP: { int request_inspection_finished = 0; txndata = TSContDataGet(contp); assert ((txndata != NULL) && (txndata->tx != NULL)); status = process_hdr(txndata, txnp, &tsib_direction_client_req); if (HDR_OUTCOME_IS_HTTP_OR_ERROR(status, txndata)) { if (status == HDR_HTTP_STATUS) { ib_log_debug_tx(txndata->tx, "HTTP code %d contp=%p", txndata->status, contp); } else { /* Ironbee set a status we don't handle. * We returned EINVAL, but we also need housekeeping to * avoid a crash in modhtp and log something bad. */ ib_log_debug_tx(txndata->tx, "Internal error %d contp=%p", txndata->status, contp); /* Ugly hack: notifications to stop modhtp bombing out */ request_inspection_finished = 1; } } else { /* Other nonzero statuses not supported */ switch(status) { case HDR_OK: /* If we're not inspecting the Request body, * we can bring forward notification of end-request * so any header-only tests run on Request phase * can abort the tx before opening a backend connection. */ if (!ib_flags_all(txndata->tx->flags, IB_TX_FINSPECT_REQBODY)) { request_inspection_finished = 1; } break; /* All's well */ case HDR_HTTP_STATUS: // FIXME: should we take the initiative here and return 500? ib_log_error_tx(txndata->tx, "Internal error: ts-ironbee requested error but no error response set."); break; case HDR_HTTP_100: /* This can't actually happen with current Trafficserver * versions, as TS will generate a 400 error without * reference to us. But in case that changes in future ... */ ib_log_error_tx(txndata->tx, "No request headers found."); break; default: ib_log_error_tx(txndata->tx, "Unhandled state arose in handling request headers."); break; } } if (request_inspection_finished) { if (!ib_flags_all(txndata->tx->flags, IB_TX_FREQ_STARTED) ) { ib_state_notify_request_started(txndata->tx->ib, txndata->tx, NULL); } if (!ib_flags_all(txndata->tx->flags, IB_TX_FREQ_FINISHED) ) { ib_state_notify_request_finished(txndata->tx->ib, txndata->tx); } } else { /* hook an input filter to watch data */ TSHttpTxnHookAdd(txnp, TS_HTTP_REQUEST_TRANSFORM_HOOK, txndata->in_data_cont); } /* Flag that we can no longer prevent a request going to backend */ ib_tx_flags_set(txndata->tx, IB_TX_FSERVERREQ_STARTED); /* Check whether Ironbee told us to block the request. * This could now come not just from process_hdr, but also * from a brought-forward notification if we aren't inspecting * a request body and notified request_finished. */ if (HTTP_CODE(txndata->status)) { TSHttpTxnHookAdd(txnp, TS_HTTP_SEND_RESPONSE_HDR_HOOK, contp); TSHttpTxnReenable(txnp, TS_EVENT_HTTP_ERROR); } else { TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); } break; } /* CLEANUP EVENTS */ case TS_EVENT_HTTP_TXN_CLOSE: { txndata = TSContDataGet(contp); TSContDestroy(txndata->out_data_cont); TSContDestroy(txndata->in_data_cont); TSContDataSet(contp, NULL); TSContDestroy(contp); if ( (txndata != NULL) && (txndata->tx != NULL) ) { ib_log_debug_tx(txndata->tx, "TXN Close: %p", (void *)contp); tsib_txn_ctx_destroy(txndata); } TSHttpTxnReenable(txnp, TS_EVENT_HTTP_CONTINUE); break; } case TS_EVENT_HTTP_SSN_CLOSE: TSDebug("ironbee", "SSN Close: %p", (void *)contp); tsib_ssn_ctx_destroy(TSContDataGet(contp)); tsib_manager_engine_cleanup(); TSHttpSsnReenable(ssnp, TS_EVENT_HTTP_CONTINUE); break; case TS_EVENT_MGMT_UPDATE: { TSDebug("ironbee", "Management update"); ib_status_t rc; rc = tsib_manager_engine_create(); if (rc != IB_OK) { TSError("[ironbee] Error creating new engine: %s", ib_status_to_string(rc)); } break; } /* if we get here we've got a bug */ default: TSError("[ironbee] *** Unhandled event %d in ironbee_plugin.", event); break; } return 0; }
ib_status_t core_audit_close(ib_provider_inst_t *lpi, ib_auditlog_t *log) { IB_FTRACE_INIT(); core_audit_cfg_t *cfg = (core_audit_cfg_t *)log->cfg_data; ib_core_cfg_t *corecfg; ib_status_t ib_rc; int sys_rc; char line[IB_LOGFORMAT_MAXLINELEN + 2]; int line_size = 0; /* Retrieve corecfg to get the AuditLogIndexFormat */ ib_rc = ib_context_module_config(log->ctx, ib_core_module(), &corecfg); if (ib_rc != IB_OK) { ib_log_alert(log->ib, "Failure accessing core module: %s", ib_status_to_string(ib_rc)); IB_FTRACE_RET_STATUS(ib_rc); } /* Close the audit log. */ if (cfg->fp != NULL) { fclose(cfg->fp); //rename temp to real sys_rc = rename(cfg->temp_path, cfg->full_path); if (sys_rc != 0) { sys_rc = errno; ib_log_error(log->ib, "Error renaming auditlog %s: %s (%d)", cfg->temp_path, strerror(sys_rc), sys_rc); IB_FTRACE_RET_STATUS(IB_EOTHER); } ib_log_info(log->ib, "AUDITLOG: %s", cfg->full_path); cfg->fp = NULL; } /* Write to the index file if using one. */ if ((cfg->index_fp != NULL) && (cfg->parts_written > 0)) { ib_lock_lock(&log->ctx->auditlog->index_fp_lock); ib_rc = core_audit_get_index_line(lpi, log, line, &line_size); if (ib_rc != IB_OK) { ib_lock_unlock(&log->ctx->auditlog->index_fp_lock); IB_FTRACE_RET_STATUS(ib_rc); } sys_rc = fwrite(line, line_size, 1, cfg->index_fp); if (sys_rc < 0) { sys_rc = errno; ib_log_error(log->ib, "Could not write to audit log index: %s (%d)", strerror(sys_rc), sys_rc); /// @todo Should retry (a piped logger may have died) fclose(cfg->index_fp); cfg->index_fp = NULL; log->ctx->auditlog->index_fp = cfg->index_fp; ib_lock_unlock(&log->ctx->auditlog->index_fp_lock); IB_FTRACE_RET_STATUS(IB_OK); } fflush(cfg->index_fp); ib_lock_unlock(&log->ctx->auditlog->index_fp_lock); } IB_FTRACE_RET_STATUS(IB_OK); }