📄 mod_cspace.c
字号:
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */#include <string.h>#include <openssl/x509.h>#include <openssl/sha.h>#include <openssl/hmac.h>#include <openssl/bio.h>#include <openssl/buffer.h>#include "apr_tables.h"#include "apr_strings.h"#include "ap_config.h"#include "mod_cspace.h"#include "http_core.h"#include "http_request.h"#include "http_protocol.h"#include "http_log.h"#include "http_main.h"#include "cspace_utils.h"#include "session.h"#include "process_request.h"#include "cspace_validator.h"#define SESSION_ID_LEN 64#define MYMIN(a, b) ((a)<(b)?(a):(b))#define UNAUTHORIZED_REDIRECT(r, u) redirect_external((r), (u))#define CARDSPACE_HEADER_PFX "cardspace_"#define CARDSPACE_HEADER_PPID "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/privatepersonalidentifier"static void remove_cspace_headers(request_rec *r);void cspace_log_error(const char *msg, pc_log_level_t level, void *cb_ctx){ ap_log_error(APLOG_MARK, level, 0, (server_rec *)cb_ctx, msg);}/*static X509 *x509_create_with_buffer(unsigned char *input, int length);static int is_valid_cert(const char *cert, const char *uri, const char *dso_filename, apr_pool_t *p);*//* moved to mod_cspace.h static void cspace_log_error(const char *msg, pc_log_level_t level, void *cb_ctx){ ap_log_error(APLOG_MARK, level, 0, (server_rec *)cb_ctx, msg);}*/static int redirect_external(request_rec *r, char *url){ /* set a "Location:" header and 302 redirect. */ printf("redirecting to: %s", url); apr_table_setn(r->headers_out, "Location", url); return HTTP_MOVED_TEMPORARILY; }#if 0static int redirect_internal(request_rec *r, char* url){ remove_cspace_headers(r); ap_internal_redirect(url, r); return OK; /*return HTTP_UNAUTHORIZED;*/}#endifstatic int find_uri(const char *uri, apr_array_header_t *a){ int i; void *tmp; tmp = a->elts; for (i = 0; i < a->nelts; i++) {#ifdef CSPACE_DEBUG printf("comparing:%s (%d), %s (%d), min=%d\n", *(char **)tmp, strlen(*(char **)tmp), uri, strlen(uri), MYMIN(strlen(*(char **)tmp), strlen(uri)));#endif if (strcmp(uri, "/") == 0) { if (strcmp(*(char **)tmp, "/") == 0) { return SUCC; } else { return FAIL; } } if (strncmp(*(char **)tmp, uri, MYMIN(strlen(*(char **)tmp), strlen(uri))) == 0) { return SUCC; } tmp = (char *)tmp + a->elt_size; } return FAIL;}/*This piece of code is used only for testing purposes*/#ifdef CSPACE_DEBUGstatic int cspace_access_check_testing(request_rec *r) { cspace_dir_cfg *dir_cfg = (cspace_dir_cfg *)ap_get_module_config( r->per_dir_config, &cspace_module); cspace_svr_cfg *svr_cfg = (cspace_svr_cfg *)ap_get_module_config( r->server->module_config, &cspace_module); printf("\n\n\nCSPACE_ACCESS_CHECK\n"); cfg_svr_printf("\tsvr cfg:", svr_cfg, "\n"); cfg_dir_printf("\tdir cfg:", dir_cfg, "\n"); printf("\tURI: %s\n\n\n\n", r->uri); return DECLINED;}#endif/* FROM http_filter.c: * * Here we deal with getting the request message body from the client. * Whether or not the request contains a body is signaled by the presence * of a non-zero Content-Length or by a Transfer-Encoding: chunked. * * Note that this is more complicated than it was in Apache 1.1 and prior * versions, because chunked support means that the module does less. * * The proper procedure is this: * * 1. Call ap_setup_client_block() near the beginning of the request * handler. This will set up all the necessary properties, and will * return either OK, or an error code. If the latter, the module should * return that error code. The second parameter selects the policy to * apply if the request message indicates a body, and how a chunked * transfer-coding should be interpreted. Choose one of * * REQUEST_NO_BODY Send 413 error if message has any body * REQUEST_CHUNKED_ERROR Send 411 error if body without Content-Length * REQUEST_CHUNKED_DECHUNK If chunked, remove the chunks for me. * REQUEST_CHUNKED_PASS If chunked, pass the chunk headers with body. * * In order to use the last two options, the caller MUST provide a buffer * large enough to hold a chunk-size line, including any extensions. * * 2. When you are ready to read a body (if any), call ap_should_client_block(). * This will tell the module whether or not to read input. If it is 0, * the module should assume that there is no message body to read. * * 3. Finally, call ap_get_client_block in a loop. Pass it a buffer and its * size. It will put data into the buffer (not necessarily a full buffer), * and return the length of the input block. When it is done reading, it will * return 0 if EOF, or -1 if there was an error. * If an error occurs on input, we force an end to keepalive. * * This step also sends a 100 Continue response to HTTP/1.1 clients if * appropriate. */static int cspace_read_request(request_rec *r, char **buf, int *retval){ apr_array_header_t *a; apr_pool_t *p = r->pool; apr_pool_t *temp_pool; int res, ret; #ifdef CSPACE_DEBUG printf("CSPACE_READ_REQUEST:\n");#endif if (apr_pool_create(&temp_pool, p) != APR_SUCCESS) return FAIL; /*TODO: should it be UNAUTHORIZED?*/ a = apr_array_make(temp_pool, 1, sizeof(char *)); ret = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK); if (ret != OK) { *retval = ret; return FAIL; /*above: module should return that error code*/ } if (ap_should_client_block(r)) { char temp_buf[HUGE_STRING_LEN + 1]; while ((res = ap_get_client_block(r, temp_buf, HUGE_STRING_LEN)) > 0) { *(temp_buf + res) = '\0'; *(const char **)apr_array_push(a) = apr_pstrdup(temp_pool, temp_buf); /*this array is free'd before the function exits*/ } } else { cspace_log_error("Cannot read request body", APLOG_WARNING, r->server);#ifdef CSPACE_DEBUG printf("ERR: should_client_block false!\n");#endif return FAIL; } *buf = apr_array_pstrcat(p, a, '\0'); /*use the request pool here*/ apr_pool_destroy(temp_pool); return SUCC; /*return (res == OK);*/}static void set_header(char *uri, char *key, char *val, void* table, void *pool){ apr_table_t *t = (apr_table_t *)table;#ifdef CSPACE_DEBUG printf("Header %s/%s:%s\n", uri, key, val);#endif /*process_context_extract info dups for us*/#ifndef DONT_INCLUDE_CS_PFX_IN_HEADERS if (uri) { apr_table_set(t, apr_pstrcat(pool, CARDSPACE_HEADER_PFX, uri, "/", key, NULL),val); } else { apr_table_set(t, apr_pstrcat(pool, CARDSPACE_HEADER_PFX, key, NULL), val); }#else /* DONT_INCLUDE_CS_PFX_IN_HEADERS */ if (uri) { apr_table_set(t, apr_pstrcat(pool, uri, "/", key, NULL), val); } else { apr_table_set(t, apr_pstrcat(pool, key, NULL), val); }#endif /* DONT_INCLUDE_CS_PFX_IN_HEADERS */}/*static int iterate_headers_remove(void *rec, const char *key, const char *val){ if (ap_strstr_c(key, CARDSPACE_HEADER_PFX)) apr_table_unset(((request_rec *)rec)->subprocess_env, key); return SUCC;}*/static void remove_cspace_headers(request_rec *r){ const apr_array_header_t *hdr = apr_table_elts(r->subprocess_env); apr_table_entry_t *elts = (apr_table_entry_t *)hdr->elts; /*apr_table_entry_t *elts = (apr_table_entry_t *) r->subprocess_env->a.elts;*/ int j = hdr->nelts; int i; for (i = 0; i < j; ++i) { if (elts[i].key) { if (ap_strstr_c(elts[i].key, CARDSPACE_HEADER_PFX)) { apr_table_unset(r->subprocess_env, elts[i].key); --i; --j; /* HACK: this was done according to the impl of apr_table_unset */ } } }}static int iterate_headers_check(void *rec, const char *key, const char *val){ if (ap_strstr_c(key, CARDSPACE_HEADER_PFX)) return FAIL; else return SUCC;}/* may be we need a config option to specify where the claims should be * added. is processing at the proxy a real use case?*/static int check_valid_headers(request_rec *r){ return apr_table_do(iterate_headers_check, NULL, r->subprocess_env, NULL);}static int set_cookie(request_rec *r, const char* session_id){ /*apr_table_set(r->headers_out, SET_COOKIE, session_id);*/ const char *cookie_header = NULL; char *cookies = NULL; size_t cookie_len = 0; /*header len*/ cookie_header = apr_table_get(r->headers_out, HTTP_COOKIE_HEADER_OUT); if (cookie_header) { /*header already set*/ if (ap_strstr_c(cookie_header, SESSION_COOKIE)) { return SUCC; /*session_id is already set*/ } else { /*session id not set, set it now*/ cookie_len = strlen(cookie_header) - strlen(HTTP_COOKIE_HEADER_OUT); if (!(cookies = apr_palloc(r->pool, cookie_len + 3 + /*3 for ";=\0"*/ strlen(SESSION_COOKIE) + MAX_SESSION_ID_LEN))) return HTTP_INTERNAL_SERVER_ERROR; strncpy(cookies, cookie_header + strlen(HTTP_COOKIE_HEADER_OUT), cookie_len); strncpy(cookies + cookie_len, ";", 1); } } else { if (!(cookies = apr_palloc(r->pool, cookie_len + 3 + /*3 for ";=\0"*/ strlen(SESSION_COOKIE) + MAX_SESSION_ID_LEN))) return HTTP_INTERNAL_SERVER_ERROR; } /*no cookie header found, or cookie not in header*/ strncpy(cookies + cookie_len, SESSION_COOKIE, strlen(SESSION_COOKIE)); strncpy(cookies + cookie_len + strlen(SESSION_COOKIE), "=", 1); strncpy(cookies + cookie_len + 1 + strlen(SESSION_COOKIE), session_id, strlen(session_id)); strncpy(cookies + cookie_len + 1 + strlen(SESSION_COOKIE) + strlen(session_id), "\0", 1); apr_table_unset(r->headers_out, HTTP_COOKIE_HEADER_OUT); apr_table_set(r->headers_out, HTTP_COOKIE_HEADER_OUT, cookies); return SUCC;}static int get_cookie(request_rec *r, char **cookies){ const char *cookie_header = NULL; size_t cookie_len; /*header len*/ cookie_header = apr_table_get(r->headers_in, HTTP_COOKIE_HEADER_IN); if (!cookie_header) return FAIL; /*no cookie header found*/ cookie_len = strlen(cookie_header); /*- strlen(HTTP_COOKIE_HEADER_IN)*/ if (!(*cookies = apr_palloc(r->pool, cookie_len))) return HTTP_INTERNAL_SERVER_ERROR; strncpy(*cookies, cookie_header /* + strlen(HTTP_COOKIE_HEADER_IN)*/, cookie_len); strncpy(*cookies + cookie_len, "\0", 1); return SUCC;}static char *get_session_id_from_cookies(char *cookies){ char *ptr = NULL; if ((cookies) && (cookies = ap_strstr(cookies, SESSION_COOKIE))) { /*cookie in hand*/ if ((cookies) && (ptr = strchr(cookies, '='))) { /*cookie structure is fine, now get the value*/ if ((ptr) && (ptr = strtok(ptr + 1, " ;\n\t\r\f"))) { /*ptr contains the valid session ID*/ printf("session id received:%s\n", ptr); printf("all cookies received: %s\n", cookies); return ptr; } } } return NULL;}/*TODO:DONE make this to handle an excluded list instead of just one uri*/static int excluded_uri(const char *uri, apr_array_header_t *excluded_list){ if (find_uri(uri, excluded_list)) return SUCC; else return FAIL;}static int cspace_login_arg_avail(request_rec *r){ if (r->args) { if (strncmp(r->args, CSPACE_DEFAULT_LOGIN_ARG, MYMIN(strlen(CSPACE_DEFAULT_LOGIN_ARG), strlen(r->args))) == 0) return SUCC; else if (ap_strstr_c(r->args, CSPACE_DEFAULT_LOGIN_AMP_ARG)) return SUCC; } return FAIL;}static int handle_session_sso(request_rec *r, cspace_dir_cfg *dir_cfg, cspace_svr_cfg *svr_cfg){ /*TODO*/ return UNAUTHORIZED_REDIRECT(r, dir_cfg->redir_uri);}static int handle_nosession_sso(request_rec *r, cspace_dir_cfg *dir_cfg, cspace_svr_cfg *svr_cfg){ char *session_id = NULL; int valid_session = FAIL; int status = FAIL; char *cookies = NULL; void *session_ctx = NULL; status = get_cookie(r, &cookies); if (status == HTTP_INTERNAL_SERVER_ERROR) return status; session_ctx = session_ctx_create(r->pool, dir_cfg->session_file, svr_cfg->session_expire); /*NB: should we return HTTP_METHOD_NOT_ALLOWED if not POST?*/ /* TODO: make the argument (tag identifying login page) a config option */ if ((cookies) && (session_id = get_session_id_from_cookies(cookies))) { if ((valid_session = handle_session(session_id, SESSION_ID_LEN, session_ctx))) return OK; } if ((cspace_login_arg_avail(r)) && (r->method_number == M_POST)) { /*TODO*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -