Exemplo n.º 1
0
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;
}
Exemplo n.º 2
0
/**
 * 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);
}
Exemplo n.º 3
0
ib_status_t ib_uuid_bin_to_ascii(
    char *str,
    const ib_uuid_t *uuid
)
{
    uuid_rc_t uuid_rc;
    size_t uuid_len = UUID_LEN_STR+1;
    ib_status_t rc = IB_OK;

    if (uuid == NULL || str == NULL) {
        return IB_EINVAL;
    }

    rc = ib_lock_lock(&g_uuid_lock);
    if (rc != IB_OK) {
        return 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) {
        return IB_EOTHER;
    }

    return rc;
}
Exemplo n.º 4
0
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;
}
Exemplo n.º 5
0
/**
 * 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);
    }
}
Exemplo n.º 6
0
///! 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;
}
Exemplo n.º 7
0
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;
}
Exemplo n.º 8
0
/**
 * 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;
}
Exemplo n.º 9
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);
}