Blame auth_mellon_cookie.c

Packit Service d6b4c9
/*
Packit Service d6b4c9
 *
Packit Service d6b4c9
 *   auth_mellon_cookie.c: an authentication apache module
Packit Service 4d483e
 *   Copyright © 2003-2007 UNINETT (http://www.uninett.no/)
Packit Service d6b4c9
 *
Packit Service d6b4c9
 *   This program is free software; you can redistribute it and/or modify
Packit Service d6b4c9
 *   it under the terms of the GNU General Public License as published by
Packit Service d6b4c9
 *   the Free Software Foundation; either version 2 of the License, or
Packit Service d6b4c9
 *   (at your option) any later version.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 *   This program is distributed in the hope that it will be useful,
Packit Service d6b4c9
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service d6b4c9
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit Service d6b4c9
 *   GNU General Public License for more details.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 *   You should have received a copy of the GNU General Public License
Packit Service d6b4c9
 *   along with this program; if not, write to the Free Software
Packit Service d6b4c9
 *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
Packit Service d6b4c9
 *
Packit Service d6b4c9
 */
Packit Service d6b4c9
Packit Service d6b4c9
#include "auth_mellon.h"
Packit Service d6b4c9
Packit Service d6b4c9
#ifdef APLOG_USE_MODULE
Packit Service d6b4c9
APLOG_USE_MODULE(auth_mellon);
Packit Service d6b4c9
#endif
Packit Service d6b4c9
Packit Service d6b4c9
/* This function retrieves the name of our cookie.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Parameters:
Packit Service d6b4c9
 *  request_rec *r       The current request. Used to find the identifier of
Packit Service d6b4c9
 *                       the cookie. We also allocate memory from r->pool.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Returns:
Packit Service d6b4c9
 *  The name of the cookie.
Packit Service d6b4c9
 */
Packit Service d6b4c9
static const char *am_cookie_name(request_rec *r)
Packit Service d6b4c9
{
Packit Service d6b4c9
    am_dir_cfg_rec *dir_cfg;
Packit Service d6b4c9
Packit Service d6b4c9
    dir_cfg = am_get_dir_cfg(r);
Packit Service d6b4c9
Packit Service d6b4c9
    return apr_pstrcat(r->pool, "mellon-", dir_cfg->varname, NULL);
Packit Service d6b4c9
}
Packit Service d6b4c9
Packit Service d6b4c9
Packit Service d6b4c9
/* Calculate the cookie parameters.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Parameters:
Packit Service d6b4c9
 *  request_rec *r       The request we should set the cookie in.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Returns:
Packit Service d6b4c9
 *  The cookie parameters as a string.
Packit Service d6b4c9
 */
Packit Service d6b4c9
static const char *am_cookie_params(request_rec *r)
Packit Service d6b4c9
{
Packit Service d6b4c9
    int secure_cookie;
Packit Service d6b4c9
    int http_only_cookie;
Packit Service d6b4c9
    const char *cookie_domain = ap_get_server_name(r);
Packit Service d6b4c9
    const char *cookie_path = "/";
Packit Service d6b4c9
    const char *cookie_samesite = "";
Packit Service 4221f6
    const char *env_var_value = NULL;
Packit Service d6b4c9
    am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
Packit Service d6b4c9
Packit Service d6b4c9
    if (cfg->cookie_domain) {
Packit Service d6b4c9
        cookie_domain = cfg->cookie_domain;
Packit Service d6b4c9
    }
Packit Service d6b4c9
Packit Service d6b4c9
    if (cfg->cookie_path) {
Packit Service d6b4c9
        cookie_path = cfg->cookie_path;
Packit Service d6b4c9
    }
Packit Service d6b4c9
Packit Service 4221f6
    if (r->subprocess_env != NULL){
Packit Service 4221f6
        env_var_value = apr_table_get(r->subprocess_env,
Packit Service 4221f6
                        AM_DISABLE_SAMESITE_ENV_VAR);
Packit Service 4221f6
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
Packit Service 4221f6
                     "%s : %s", AM_DISABLE_SAMESITE_ENV_VAR, env_var_value);
Packit Service 4221f6
    }
Packit Service 4221f6
Packit Service 4221f6
    if (env_var_value == NULL){
Packit Service d71f4a
        if ((cfg->cookie_samesite != am_samesite_default) &&
Packit Service d71f4a
            (apr_table_get(r->notes, AM_FORCE_SAMESITE_NONE_NOTE) != NULL)) {
Packit Service d71f4a
            cookie_samesite = "; SameSite=None";
Packit Service d71f4a
        }
Packit Service d71f4a
        else if (cfg->cookie_samesite == am_samesite_lax) {
Packit Service 4221f6
            cookie_samesite = "; SameSite=Lax";
Packit Service 4221f6
        } else if (cfg->cookie_samesite == am_samesite_strict) {
Packit Service 4221f6
            cookie_samesite = "; SameSite=Strict";
Packit Service 4221f6
        } else if (cfg->cookie_samesite == am_samesite_none) {
Packit Service 4221f6
            cookie_samesite = "; SameSite=None";
Packit Service 4221f6
        }
Packit Service d6b4c9
    }
Packit Service d6b4c9
Packit Service d6b4c9
    secure_cookie = cfg->secure;
Packit Service d6b4c9
    http_only_cookie = cfg->http_only;
Packit Service d6b4c9
Packit Service d6b4c9
    return apr_psprintf(r->pool,
Packit Service d6b4c9
                        "Version=1; Path=%s; Domain=%s%s%s%s;",
Packit Service d6b4c9
                        cookie_path, cookie_domain,
Packit Service d6b4c9
                        http_only_cookie ? "; HttpOnly" : "",
Packit Service d6b4c9
                        secure_cookie ? "; secure" : "",
Packit Service d6b4c9
                        cookie_samesite);
Packit Service d6b4c9
}
Packit Service d6b4c9
Packit Service d6b4c9
Packit Service d6b4c9
/* This functions finds the value of our cookie.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Parameters:
Packit Service d6b4c9
 *  request_rec *r       The request we should find the cookie in.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Returns:
Packit Service d6b4c9
 *  The value of the cookie, or NULL if we don't find the cookie.
Packit Service d6b4c9
 */
Packit Service d6b4c9
const char *am_cookie_get(request_rec *r)
Packit Service d6b4c9
{
Packit Service d6b4c9
    am_req_cfg_rec *req_cfg;
Packit Service d6b4c9
    const char *name;
Packit Service d6b4c9
    const char *value;
Packit Service d6b4c9
    const char *cookie;
Packit Service d6b4c9
    char *buffer, *end;
Packit Service d6b4c9
Packit Service d6b4c9
    /* don't run for subrequests */
Packit Service d6b4c9
    if (r->main) {
Packit Service d6b4c9
        ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
Packit Service d6b4c9
                     "cookie_get: Subrequest, so return NULL");        
Packit Service d6b4c9
        return NULL;
Packit Service d6b4c9
    }
Packit Service d6b4c9
Packit Service d6b4c9
    /* Check if we have added a note on the current request. */
Packit Service d6b4c9
    req_cfg = am_get_req_cfg(r);
Packit Service d6b4c9
    value = req_cfg->cookie_value;
Packit Service d6b4c9
    if(value != NULL) {
Packit Service d6b4c9
        return value;
Packit Service d6b4c9
    }
Packit Service d6b4c9
Packit Service d6b4c9
Packit Service d6b4c9
    name = am_cookie_name(r);
Packit Service d6b4c9
Packit Service d6b4c9
    cookie = apr_table_get(r->headers_in, "Cookie");
Packit Service d6b4c9
    if(cookie == NULL) {
Packit Service d6b4c9
        return NULL;
Packit Service d6b4c9
    }
Packit Service d6b4c9
Packit Service d6b4c9
    for(value = ap_strstr_c(cookie, name); value != NULL;
Packit Service d6b4c9
        value = ap_strstr_c(value + 1, name)) {
Packit Service d6b4c9
Packit Service d6b4c9
        if(value != cookie) {
Packit Service d6b4c9
            /* value isn't pointing to the start of the string. */
Packit Service d6b4c9
            switch(value[-1]) {
Packit Service d6b4c9
                /* We allow the name in the cookie-string to be
Packit Service d6b4c9
                 * preceeded by [\t; ]. Note that only ' ' should be used
Packit Service d6b4c9
                 * by browsers. We test against the others just to be sure.
Packit Service d6b4c9
                 */
Packit Service d6b4c9
            case '\t':
Packit Service d6b4c9
            case ';':
Packit Service d6b4c9
            case ' ':
Packit Service d6b4c9
                break;
Packit Service d6b4c9
            default:
Packit Service d6b4c9
                /* value isn't preceeded by one of the listed characters, and
Packit Service d6b4c9
                 * therefore we assume that it is part of another cookie.
Packit Service d6b4c9
                 */
Packit Service d6b4c9
                continue; /* Search for the next instance of the name. */
Packit Service d6b4c9
            }
Packit Service d6b4c9
        }
Packit Service d6b4c9
Packit Service d6b4c9
        if(value[strlen(name)] != '=') {
Packit Service d6b4c9
            /* We don't have an equal-sign right after the name. Therefore we
Packit Service d6b4c9
             * assume that what we have matched is only part of a longer name.
Packit Service d6b4c9
             * We continue searching.
Packit Service d6b4c9
             */
Packit Service d6b4c9
            continue;
Packit Service d6b4c9
        }
Packit Service d6b4c9
Packit Service d6b4c9
        /* Now we have something that matches /[^ ,\t]<name>=/. The value
Packit Service d6b4c9
         * (following the equal-sign) can be found at value + strlen(name) + 1.
Packit Service d6b4c9
         */
Packit Service d6b4c9
        value += strlen(name) + 1;
Packit Service d6b4c9
Packit Service d6b4c9
        /* The cookie value may be double-quoted. */
Packit Service d6b4c9
        if(*value == '"') {
Packit Service d6b4c9
            value += 1;
Packit Service d6b4c9
        }
Packit Service d6b4c9
Packit Service d6b4c9
        buffer = apr_pstrdup(r->pool, value);
Packit Service d6b4c9
        end = strchr(buffer, '"');
Packit Service d6b4c9
        if(end) {
Packit Service d6b4c9
            /* Double-quoted string. */
Packit Service d6b4c9
            *end = '\0';
Packit Service d6b4c9
        }
Packit Service d6b4c9
        end = strchr(buffer, ';');
Packit Service d6b4c9
        if(end) {
Packit Service d6b4c9
            *end = '\0';
Packit Service d6b4c9
        }
Packit Service d6b4c9
Packit Service d6b4c9
        return buffer;
Packit Service d6b4c9
    }
Packit Service d6b4c9
Packit Service d6b4c9
    /* We didn't find the cookie. */
Packit Service d6b4c9
    return NULL;
Packit Service d6b4c9
}
Packit Service d6b4c9
Packit Service d6b4c9
Packit Service d6b4c9
/* This function sets the value of our cookie.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Parameters:
Packit Service d6b4c9
 *  request_rec *r       The request we should set the cookie in.
Packit Service d6b4c9
 *  const char *id       The value ve should store in the cookie.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Returns:
Packit Service d6b4c9
 *  Nothing.
Packit Service d6b4c9
 */
Packit Service d6b4c9
void am_cookie_set(request_rec *r, const char *id)
Packit Service d6b4c9
{
Packit Service d6b4c9
    am_req_cfg_rec *req_cfg;
Packit Service d6b4c9
    const char *name;
Packit Service d6b4c9
    const char *cookie_params;
Packit Service d6b4c9
    char *cookie;
Packit Service d6b4c9
Packit Service d6b4c9
    if (id == NULL)
Packit Service d6b4c9
        return;
Packit Service d6b4c9
Packit Service d6b4c9
    name = am_cookie_name(r);
Packit Service d6b4c9
    cookie_params = am_cookie_params(r);
Packit Service d6b4c9
Packit Service d6b4c9
    cookie = apr_psprintf(r->pool, "%s=%s; %s", name, id, cookie_params);
Packit Service d6b4c9
    ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server,
Packit Service d6b4c9
                 "cookie_set: %s", cookie);
Packit Service d6b4c9
Packit Service d6b4c9
    /* Setting the headers inn err_headers_out ensures that they will be
Packit Service d6b4c9
     * sent for all responses.
Packit Service d6b4c9
     */
Packit Service d6b4c9
    apr_table_addn(r->err_headers_out, "Set-Cookie", cookie);
Packit Service d6b4c9
Packit Service d6b4c9
    /* Add a note on the current request, to allow us to retrieve this
Packit Service d6b4c9
     * cookie in the current request.
Packit Service d6b4c9
     */
Packit Service d6b4c9
    req_cfg = am_get_req_cfg(r);
Packit Service d6b4c9
    req_cfg->cookie_value = apr_pstrdup(r->pool, id);
Packit Service d6b4c9
}
Packit Service d6b4c9
Packit Service d6b4c9
Packit Service d6b4c9
/* This function deletes the cookie.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Parameters:
Packit Service d6b4c9
 *  request_rec *r       The request we should clear the cookie in. We will
Packit Service d6b4c9
 *                       allocate any neccesary memory from r->pool.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 * Returns:
Packit Service d6b4c9
 *  Nothing.
Packit Service d6b4c9
 */
Packit Service d6b4c9
void am_cookie_delete(request_rec *r)
Packit Service d6b4c9
{
Packit Service d6b4c9
    const char *name;
Packit Service d6b4c9
    const char *cookie_params;
Packit Service d6b4c9
    char *cookie;
Packit Service d6b4c9
Packit Service d6b4c9
    name = am_cookie_name(r);
Packit Service d6b4c9
    cookie_params = am_cookie_params(r);
Packit Service d6b4c9
Packit Service d6b4c9
Packit Service d6b4c9
    /* Format a cookie. To delete a cookie we set the expires-timestamp
Packit Service d6b4c9
     * to the past.
Packit Service d6b4c9
     */
Packit Service d6b4c9
    cookie = apr_psprintf(r->pool, "%s=NULL;"
Packit Service d6b4c9
                          " expires=Thu, 01-Jan-1970 00:00:00 GMT;"
Packit Service d6b4c9
                          " %s",
Packit Service d6b4c9
                          name, cookie_params);
Packit Service d6b4c9
Packit Service d6b4c9
    apr_table_addn(r->err_headers_out, "Set-Cookie", cookie);
Packit Service d6b4c9
}
Packit Service d6b4c9
Packit Service d6b4c9
/* Get string that is used to tie a session to a specific cookie.
Packit Service d6b4c9
 *
Packit Service d6b4c9
 *  request_rec *r       The current request.
Packit Service d6b4c9
 * Returns:
Packit Service d6b4c9
 *  The cookie token, as a fixed length byte buffer.
Packit Service d6b4c9
 */
Packit Service d6b4c9
const char *am_cookie_token(request_rec *r)
Packit Service d6b4c9
{
Packit Service d6b4c9
    const char *cookie_name = am_cookie_name(r);
Packit Service d6b4c9
    const char *cookie_domain = ap_get_server_name(r);
Packit Service d6b4c9
    const char *cookie_path = "/";
Packit Service d6b4c9
    am_dir_cfg_rec *cfg = am_get_dir_cfg(r);
Packit Service d6b4c9
Packit Service d6b4c9
    if (cfg->cookie_domain) {
Packit Service d6b4c9
        cookie_domain = cfg->cookie_domain;
Packit Service d6b4c9
    }
Packit Service d6b4c9
Packit Service d6b4c9
    if (cfg->cookie_path) {
Packit Service d6b4c9
        cookie_path = cfg->cookie_path;
Packit Service d6b4c9
    }
Packit Service d6b4c9
Packit Service d6b4c9
    return apr_psprintf(r->pool, "Name='%s' Domain='%s' Path='%s'",
Packit Service d6b4c9
                        cookie_name,
Packit Service d6b4c9
                        cookie_domain,
Packit Service d6b4c9
                        cookie_path
Packit Service d6b4c9
                        );
Packit Service d6b4c9
}