814 lines
25 KiB
C
814 lines
25 KiB
C
/****************************************************************************
|
|
|
|
mod_dav_pgsql (DASL) for apache 2.X
|
|
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
|
CopyRight(C) 2006 Netomi Inc. All Rights reserved.
|
|
Author : elenoa lazyfake (elenoa@solutionbox.co.kr)
|
|
|
|
$Id: share.c,v 1.8 2007/02/22 08:22:13 elenoa Exp $
|
|
|
|
Redistribution and use in source and binary forms, with or with out
|
|
modification, are not permitted in outside of SolutionBox Inc.
|
|
|
|
****************************************************************************/
|
|
#include <unistd.h>
|
|
#include <ctype.h>
|
|
#include <math.h>
|
|
|
|
#include <httpd.h>
|
|
#include <http_config.h>
|
|
#include <http_protocol.h>
|
|
#include <http_log.h>
|
|
#include <http_core.h> /* for ap_construct_url */
|
|
#include <http_request.h>
|
|
|
|
#include <apr_strings.h>
|
|
#include <apr_signal.h>
|
|
|
|
#include "dav_repos.h"
|
|
#include "dbms.h"
|
|
#include "util.h"
|
|
#include "share_common.h"
|
|
#include "share_account.h"
|
|
#include "share_fhs_stat.h"
|
|
#include "share_anonymous.h"
|
|
|
|
/* for anonymous */
|
|
static struct shm_mgnt anon_mgnt = {
|
|
NULL, NULL, SHM_ANON, SHM_ANON_LOCK, 0, 0
|
|
};
|
|
|
|
struct anonymous *g_ar;
|
|
static int maxanon = 0;
|
|
|
|
int dav_initialize_shared_anonymous(dav_repos_server_conf *dsc, server_rec *s, apr_pool_t *p)
|
|
{
|
|
if (!dsc->max_anony_realm || (maxanon = atoi(dsc->max_anony_realm)) <= 0) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "OPENDAV: initialize_shared_memory: "
|
|
"MaxAnonymous <= 0 (%d)", maxanon);
|
|
return !OK;
|
|
}
|
|
|
|
/* anonymous control : calculate shared memory size from max_anony_realm value */
|
|
anon_mgnt.size = (sizeof(struct anonymous) * maxanon);
|
|
g_ar = (struct anonymous *)dav_shared_get_new_memory(&anon_mgnt, s, p, false);
|
|
|
|
if (!g_ar) return !OK;
|
|
|
|
return OK;
|
|
}
|
|
|
|
void dav_cleanup_shared_anonymous()
|
|
{
|
|
if (anon_mgnt.shm) {
|
|
apr_shm_detach(anon_mgnt.shm);
|
|
}
|
|
|
|
if (anon_mgnt.lock) {
|
|
apr_global_mutex_destroy(anon_mgnt.lock);
|
|
}
|
|
}
|
|
|
|
// CHG 2012-04-20 huibong
|
|
// 본 함수는 HOOK 처리된 opendav 의 최초 진입함수로서 요청에 대한 무인증 여부를 확인함.
|
|
// 하지만 본 함수의 flow 가 불필요 loop 를 돌려서 처리하기 때문에.. 무인증 설정 정보가 많을 경우..
|
|
// 전체 응답 성능을 저하시켜... 전체적으로 수정 처리함.
|
|
|
|
static int dav_find_location(request_rec *r, const char * svc_name, const char * uri, bool uricaseignore, bool urihassvcname)
|
|
{
|
|
// DB 처리용 변수 생성.
|
|
char * temp_uri = NULL;
|
|
char * db_uri = apr_pcalloc(r->pool, MaxSizeOfPathLength);
|
|
char * red_uri = NULL;
|
|
char * e_uri = NULL;
|
|
|
|
char * query;
|
|
ap_dbd_t *db;
|
|
apr_dbd_results_t *res = NULL;
|
|
apr_dbd_row_t *row = NULL;
|
|
apr_status_t rv;
|
|
char tblname[20] = { 0 };
|
|
|
|
int ntuple;
|
|
char * host_name = NULL;
|
|
unsigned int n = 0;
|
|
|
|
char * p3 = NULL;
|
|
|
|
// loop 처리 관련 변수
|
|
int j;
|
|
|
|
struct account_cache * ac = NULL;
|
|
ac = dav_shared_ac_get_by_vol_not_timeout(svc_name);
|
|
if (ac == NULL)
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_find_location: svcname[%s] info not found.", svc_name);
|
|
return !OK;
|
|
}
|
|
|
|
/* UTF-8. change UHC(CP949) */
|
|
temp_uri = transformDBCharacter(r, (char *)uri, "dav_find_location");
|
|
|
|
// 2012-08-10 CHG huibong
|
|
// 무인증 URI 상에 \ 및 ' 의 특수문자가 포함된 경우 RCDB 상에 쿼리가 정상적으로 되지 않는 문제가 발생.
|
|
// 이를 해결하기 위해 특수문자를 RCDB 가 인식할 수 있도록 dav_repos_replace_unsafe_chars() 함수를 이용하여 변환 처리하도록 수정
|
|
memset(db_uri, 0x00, MaxSizeOfPathLength);
|
|
dav_repos_replace_unsafe_chars(temp_uri, db_uri);
|
|
|
|
p3 = strchr(db_uri, '?');
|
|
if (p3)
|
|
*p3 = '\0';
|
|
|
|
// 2014-04-24 : dadamin
|
|
// where 구문에 파티셔닝 기준값, depth 추가
|
|
int nDepth;
|
|
nDepth = ap_count_dirs(db_uri);
|
|
|
|
/* remake redirected uri */
|
|
// CHG 2010-08-11 대소문자 구분여부에 따른 Query 변경.
|
|
|
|
// ChG 2012-04-19 huibong
|
|
// - Query 구문상에 MAX, GROUP BY, ORDER BY 조건식이 아래 코드의 Random 선택 코드로 인해 무의미하므로 수정 처리.
|
|
|
|
if (uricaseignore == true) // URI 대소문자 무시 서비스인 경우
|
|
{
|
|
query = apr_psprintf(r->pool,
|
|
"SELECT host_name, is_cache, filename_hash "
|
|
"FROM %s "
|
|
// CHG 2014.10.02 dadamin
|
|
// WHERE 절 구문 중 조건과 조건 사이 공백 추가
|
|
// 현재 정상 수행됨을 확인 하였지만 만약에 있을 오류 대비하여 수정함
|
|
// e.g) SELECT ... WHERE sp_svc_tran_id = 214AND depth = 3... (정상 수행됨)
|
|
"WHERE sp_svc_tran_id = %s "
|
|
"AND depth = %d "
|
|
"AND %s = lower('/%s%s') AND deleted_yn = 'N' "
|
|
, dav_get_target_table(ac->tran_id, tblname)
|
|
, ac->tran_id, nDepth
|
|
// 2014.06.12
|
|
// 신규 형상(9.3)에서 대소문자 구분은 인덱스로 지원하지 않음
|
|
, dav_use_display_name() == 0 ? "lower(uri)" : "uri"
|
|
, ac->tran_id, db_uri
|
|
);
|
|
}
|
|
else
|
|
{
|
|
// 대소문자 구분을 하는 경우
|
|
query = apr_psprintf(r->pool,
|
|
"SELECT host_name, is_cache, filename_hash "
|
|
"FROM %s "
|
|
// CHG 2014.10.02 dadamin
|
|
// WHERE 절 구문 중 조건과 조건 사이 공백 추가
|
|
// 현재 정상 수행됨을 확인 하였지만 만약에 있을 오류 대비하여 수정함
|
|
// e.g) SELECT ... WHERE sp_svc_tran_id = 214AND depth = 3... (정상 수행됨)
|
|
"WHERE sp_svc_tran_id = %s "
|
|
"AND depth = %d "
|
|
"AND uri = '/%s%s' AND deleted_yn = 'N' "
|
|
, dav_get_target_table(ac->tran_id, tblname)
|
|
, ac->tran_id, nDepth, ac->tran_id, db_uri
|
|
);
|
|
}
|
|
|
|
db = dav_repos_get_db(r);
|
|
if (db == NULL)
|
|
{
|
|
db_error_message(db, "dav_find_location: database acquire timeout", 0);
|
|
return DECLINED;
|
|
}
|
|
|
|
rv = apr_dbd_select(db->driver, r->pool, db->handle, &res, query, 1);
|
|
if (rv)
|
|
{
|
|
db_error_message(db, "dav_find_location: select", rv);;
|
|
dav_repos_release_db(r, db, rv);
|
|
|
|
return DECLINED;
|
|
}
|
|
|
|
ntuple = apr_dbd_num_tuples(db->driver, res);
|
|
|
|
// 조회 결과가 존재하지 않을 경우
|
|
if (ntuple < 1)
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_find_location: request uri not found [%s][%s]", svc_name, db_uri);
|
|
dav_repos_release_db(r, db, rv);
|
|
return DECLINED;
|
|
}
|
|
|
|
// CHG 2012-04-19 huibong
|
|
// Redirection 처리 장비 선택 로직 전면 수정..
|
|
// 기존 코드 로직 중 불필요한 loop 로직 존재..
|
|
// 그리고 무조건 301 Redirection 응답이므로... 부하 분산을 위해 자기 자신 장비가 우선이 아니라.. 살아 있는 장비 중 random 선택 처리.
|
|
host_name = NULL;
|
|
|
|
// 해당 장비가 1대 인 경우
|
|
if (ntuple == 1)
|
|
{
|
|
rv = solbox_apr_dbd_get_row(db->driver, r->pool, res, &row, 0);
|
|
host_name = apr_pstrdup(r->pool, apr_dbd_get_entry(db->driver, row, 0));
|
|
}
|
|
else // 해당 장비가 여러 대인 경우
|
|
{
|
|
// C99을 지원하는 컴파일일 경우 배열의 인자로 처리 가능 만약을 대비하여 동적할당 방식으로 수정
|
|
int * host_alive_index;
|
|
int host_alive_count = 0;
|
|
|
|
// 메모리 할당
|
|
host_alive_index = (int *)calloc(ntuple, sizeof(int));
|
|
|
|
// 메모리 할당 실패 시 => 첫번째 row의 값을 사용
|
|
if (host_alive_index == NULL)
|
|
{
|
|
rv = solbox_apr_dbd_get_row(db->driver, r->pool, res, &row, 0);
|
|
host_name = apr_pstrdup(r->pool, apr_dbd_get_entry(db->driver, row, 0));
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_find_location: out of memory. default return first [%s][%s][%s]", svc_name, db_uri, host_name);
|
|
}
|
|
else
|
|
{
|
|
// 조회된 장비가 Alive 상태인지 검사한다.
|
|
for (j = 0; j < ntuple; j++)
|
|
{
|
|
rv = solbox_apr_dbd_get_row(db->driver, r->pool, res, &row, j);
|
|
|
|
if (dav_shared_du_is_alive(apr_dbd_get_entry(db->driver, row, 0)) != 0)
|
|
{
|
|
host_alive_index[host_alive_count] = j;
|
|
host_alive_count++;
|
|
}
|
|
}
|
|
|
|
// Alive 장비의 갯수 확인
|
|
if (host_alive_count <= 0)
|
|
{
|
|
// Alive 상태 장비가 없는 경우... 첫번째 장비 정보 사용.
|
|
rv = solbox_apr_dbd_get_row(db->driver, r->pool, res, &row, 0);
|
|
host_name = apr_pstrdup(r->pool, apr_dbd_get_entry(db->driver, row, 0));
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_find_location: alive host nothing. default return first [%s][%s][%s]", svc_name, db_uri, host_name);
|
|
}
|
|
else
|
|
{
|
|
// Alive 상태의 장비가 여러대 인 경우...
|
|
// Random 선택
|
|
apr_generate_random_bytes((unsigned char *)&n, sizeof(int));
|
|
n = n % host_alive_count;
|
|
|
|
rv = solbox_apr_dbd_get_row(db->driver, r->pool, res, &row, host_alive_index[n]);
|
|
host_name = apr_pstrdup(r->pool, apr_dbd_get_entry(db->driver, row, 0));
|
|
|
|
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "dav_find_location: alive target random select [%s][%s][%s]", svc_name, db_uri, host_name);
|
|
}
|
|
|
|
// 메모리 해제
|
|
free(host_alive_index);
|
|
}
|
|
}
|
|
|
|
// RCDB 접속 해제
|
|
dav_repos_release_db(r, db, rv);
|
|
|
|
// 2014-06-11 dadamin uri query 구문 인코딩 방지
|
|
p3 = strchr(uri, '?');
|
|
if (p3)
|
|
*p3 = '\0';
|
|
|
|
// Redirect 처리용 URI 생성
|
|
if (urihassvcname)
|
|
red_uri = apr_pstrcat(r->pool, dav_http_scheme(r), "://", host_name, "/dav/", svc_name, uri, NULL);
|
|
else
|
|
red_uri = apr_pstrcat(r->pool, dav_http_scheme(r), "://", host_name, "/dav", uri, NULL);
|
|
|
|
e_uri = ap_os_escape_path(r->pool, red_uri, 1);
|
|
|
|
if (r->parsed_uri.query)
|
|
e_uri = apr_pstrcat(r->pool, e_uri, "?", r->parsed_uri.query, NULL);
|
|
|
|
//ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "dav_shared_ar_check_request: redirect uri[%s] escape uri[%s]", red_uri, e_uri);
|
|
|
|
apr_table_setn(r->headers_out, "Location", apr_pstrdup(r->pool, e_uri));
|
|
ap_parse_uri(r, e_uri);
|
|
|
|
return OK;
|
|
}
|
|
|
|
int dav_shared_ar_check_request(request_rec *r)
|
|
{
|
|
|
|
#if defined(__OPENDISK_SOLUTION__) || defined(__OPENDAV_SHARED_NOT_USE)
|
|
return DECLINED;
|
|
#else
|
|
|
|
dav_repos_server_conf *dsc = NULL;
|
|
|
|
const char * domain_name;
|
|
const char * p1;
|
|
const char * p2;
|
|
|
|
// 서비스명, uri, 무인증 폴더 정보 저장을 위한 변수
|
|
char * svc_name = NULL;
|
|
char * uri = NULL;
|
|
char * folder_name = NULL;
|
|
int svc_name_len = 0;
|
|
int folder_name_len = 0;
|
|
|
|
// 무인증에서 redirect 처리되어 들어오는 요청인지 여부 저장.
|
|
bool is_redirect_request = false;
|
|
|
|
// 각 서비스별 URI 대소문자 구분 여부 정보를 저장하기 위한 변수. true: URI 대소문자 무시, false: URI 대소문자 구분 (default)
|
|
int result = 0;
|
|
bool is_uricaseignore = false;
|
|
|
|
// loop 처리 관련 변수
|
|
int i = 0;
|
|
|
|
|
|
// request 값이 NULL 경우
|
|
if (!r)
|
|
return DECLINED;
|
|
|
|
|
|
// 무인증 관련 공유메모리 값이 NULL 인 경우
|
|
if (!g_ar)
|
|
return DECLINED;
|
|
|
|
// conf 정보를 가져올 수 없는 경우
|
|
dsc = dav_repos_get_server_conf(r->server);
|
|
if (!dsc)
|
|
return DECLINED;
|
|
|
|
|
|
// 1. 무인증에 대한 처리는 GET 요청에 대해서만 허용한다. 나머지 요청은 opendav 모듈로 통과 처리.
|
|
if (r->method_number != M_GET)
|
|
{
|
|
return OK;
|
|
}
|
|
|
|
// 2. HTTP Header 상에 인증 관련 Authorization 정보가 존재하는 경우.. 양방향 인증으로 처리되도록 통과 처리.
|
|
if (apr_table_get(r->headers_in, "Authorization") != NULL)
|
|
{
|
|
return OK;
|
|
}
|
|
|
|
// 3. 요청에서 서비스 name 정보를 추출한다. ( 해당 서비스의 무인증 경로 요청인지 확인하기 위해 필요)
|
|
// - HTTP Header 의 Host: 정보를 추출한다.
|
|
// - 추출된 정보는 nctest.ktsh.co.kr, bd-04-fhs001.ktsh.co.kr, 222.122.165.9 이 될 수 있음.
|
|
// - 추출 정보가 현재 장비명과 동일할 경우... URL 에서 서비스 name 정보 추출 시도.
|
|
// - 추출 정보에서 IDC Domain 정보가 존재하는지 확인하여..
|
|
// -- 존재할 경우 서비스 name 정보로 사용한다.
|
|
// -- 존재하지 않을 경우 URL 에서 서비스 name 정보 추출 시도
|
|
|
|
if (!(domain_name = apr_table_get(r->headers_in, "Host")))
|
|
{
|
|
// HTTP Header 상에 Host 정보가 존재하지 않을 경우
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_check_request: http Host tag not found. declined.");
|
|
return DECLINED;
|
|
}
|
|
else
|
|
{
|
|
// 추출된 정보가 현재 장비명과 동일하지 비교. ( 대소문자 무시하고 비교 )
|
|
if (strcasecmp(domain_name, dsc->host_name) != 0)
|
|
{
|
|
// 장비명과 동일하지 않은 경우...
|
|
// IDC Domain Name 정보가 동일하지.. Host 추출 정보와 장비명을 비교한다. ( 대소문자 무시 )
|
|
p1 = strchr(domain_name, '.');
|
|
p2 = strchr(dsc->host_name, '.');
|
|
|
|
if (p1 != NULL && strcasecmp(p1, p2) == 0)
|
|
{
|
|
// 동일한 경우...
|
|
// 서비스 name 정보로 사용한다.
|
|
svc_name_len = (p1 - domain_name);
|
|
|
|
svc_name = apr_pstrdup(r->pool, domain_name);
|
|
*(svc_name + svc_name_len) = '\0';
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// 위에서 서비스 Name 추출이 실패한 경우.. URL 에서 서비스 Name 정보를 추출 시도한다.
|
|
|
|
// 4. 우선 URL 에 대한 확인 및 필요시 변환 처리.
|
|
ap_unescape_url(r->unparsed_uri);
|
|
// 공유 메모리에 UTF-8로 저장되어 있기 때문에 변환 필요
|
|
uri = transformUTF8(r, r->unparsed_uri, "dav_shared_ar_check_request");
|
|
|
|
// 5. URL 에서 무인증 폴더 정보를 추출한다.
|
|
// 추가로 앞에서 서비스 Name 정보를 추출하지 못한 경우.. 서비스 Name 정보도 추출 처리한다.
|
|
// 일반, 무인증 요청 : /svc1_test/TEMP7.txt or /a
|
|
// 양방향 관련 요청 : /dav/svc1_test/temp1.txt ( /dav/ 경로명 : HTTP Authorization tag 존재로 인해 상위에서 우선 return 처리됨.)
|
|
// 무인증 redirect 처리 후 : /dav/nctest/SVC1_TEST/temp2.txt ( /dav/ 서비스 Name / 경로명 )
|
|
|
|
// 5-1 uri 의 길이값을 확인
|
|
// /로 시작해야 하고.. 뒤에 경로 정보가 들어 있어야 하므로...
|
|
// 최소 형식은 /a/a, /dav 의 4 byte 이상이어야 한다.
|
|
if (strlen(uri) < 4)
|
|
{
|
|
// 무인증 uri 규칙 위배 상황이고.. Authorization 정보도 존재하지 않으므로.. 거부 처리.
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_check_request: uri not valid. length too small [%s]", uri);
|
|
return DECLINED;
|
|
}
|
|
|
|
// 5-2 우선 /dav/ 로 시작하는 URI 인지 확인.
|
|
if (strstr(uri, "/dav/") == uri)
|
|
{
|
|
// /dav/ 로 시작하는 uri 인 경우..
|
|
// /dav/ 로 시작하는 부분을 건너뛰고... 다음 문자를 서비스 Name 으로 처리.... 그 다음을 경로로 처리..
|
|
|
|
p1 = uri;
|
|
p1 = p1 + 5; // p1 -> nctest/SVC1_TEST/temp2.txt 형식
|
|
|
|
p2 = strchr(p1, '/'); // p2 -> /SVC1_TEST/temp2.txt 형식
|
|
if (p2 == NULL)
|
|
{
|
|
// 무인증 redirect 처리 규칙 위배 상황이고.. Authorization 정보도 존재하지 않으므로.. 거부 처리.
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_check_request: redirect uri format not valid [%s]", uri);
|
|
return DECLINED;
|
|
}
|
|
|
|
// 서비스 Name 정보를 추출하지 못한 경우...
|
|
if (svc_name == NULL)
|
|
{
|
|
svc_name_len = (p2 - p1);
|
|
svc_name = apr_pstrdup(r->pool, p1);
|
|
*(svc_name + svc_name_len) = '\0';
|
|
}
|
|
|
|
// 무인증 폴더 정보를 추출한다.
|
|
// 정상 : /SVC1_TEST/a.txt 형식
|
|
// 오류 : /SVC1_TEST , // , //a.txt
|
|
|
|
p2 = p2 + 1; // p2 -> SVC1_TEST/a.txt 형식
|
|
p1 = strchr(p2, '/');
|
|
if (p1 == NULL)
|
|
{
|
|
// 무인증 redirect 처리 규칙 위배 상황이고.. Authorization 정보도 존재하지 않으므로.. 거부 처리.
|
|
//ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_check_request: annoymous uri format not valid [%s]", uri );
|
|
return DECLINED;
|
|
}
|
|
else
|
|
{
|
|
folder_name_len = (p1 - p2);
|
|
|
|
if (folder_name_len < 1) // 구조가 a/ 구조가 아닌 경우 즉.. //
|
|
{
|
|
// 무인증 요청 규칙 위배이므로 거부 처리.
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_check_request: annoymous folder name length not valid [%s]", uri);
|
|
return DECLINED;
|
|
}
|
|
else
|
|
{
|
|
folder_name = apr_pstrdup(r->pool, p2);
|
|
*(folder_name + folder_name_len) = '\0'; // folder_name -> SVC1_TEST 형식
|
|
}
|
|
}
|
|
|
|
// redirect 처리되어 다시 들어온 요청임.
|
|
is_redirect_request = true;
|
|
}
|
|
else
|
|
{
|
|
// /dav/ 로 시작하지 않는 경우...
|
|
// 정상 : /svc1_test/temp7.txt,
|
|
// 특수 : /test.html ( 특정 고객사의 alive 체크 관련 지원 사항 ) => 그냥 OK 로 통과 처리.
|
|
// 오류 : //, //a.txt
|
|
|
|
p1 = uri; // p1 -> /svc1_test/temp7.txt
|
|
p1 = p1 + 1; // p1 -> svc1_test/temp7.txt
|
|
|
|
p2 = strchr(p1, '/'); // p2 -> /temp7.txt
|
|
if (p2 == NULL)
|
|
{
|
|
// 원래는 양방향 규칙 위배 상황이지만..
|
|
// 특수한 상황으로 /test.html , /ok.html 등와 같이 고객사 지원 요청이 존재하여.. 그냥 통과 처리한다.
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_check_request: uri format not valid.. but pass! [%s]", uri);
|
|
return OK;
|
|
}
|
|
|
|
folder_name_len = (p2 - p1);
|
|
if (folder_name_len < 1) // 구조가 a/ 구조가 아닌 경우 즉.. //
|
|
{
|
|
// 무인증 요청 규칙 위배이므로 거부 처리.
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_check_request: annoymous folder name length not valid [%s]", uri);
|
|
return DECLINED;
|
|
}
|
|
else
|
|
{
|
|
folder_name = apr_pstrdup(r->pool, p1);
|
|
*(folder_name + folder_name_len) = '\0'; // folder_name -> svc1_test 형식
|
|
}
|
|
}
|
|
|
|
// 6. 서비스 Name 정보를 확인하여 추출하지 못한 경우.. 서비스 거부 처리.
|
|
if (svc_name == NULL)
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_check_request: svc name not found. http host info[%s] uri[%s]", domain_name, uri);
|
|
return DECLINED;
|
|
}
|
|
|
|
// 6-1. 폴더 Name 정보를 확인하여 추출하지 못한 경우..그냥 통과 처리
|
|
if (folder_name == NULL)
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "dav_shared_ar_check_request: folder name not found. svc_name[%s] uri[%s]. pass!", svc_name, uri);
|
|
return OK;
|
|
}
|
|
|
|
// 7. 해당 서비스의 대소문자 무시 여부를 판단한다.
|
|
result = dav_shared_is_uri_ignore_case_by_svcname(svc_name);
|
|
if (result == 1) // URI 대소문자 무시 서비스인 경우
|
|
{
|
|
is_uricaseignore = true;
|
|
}
|
|
else
|
|
{
|
|
// 만약 dav_shared_is_uri_ignore_case 호출시 오류가 발생한 경우.. 양방향 기본은 대소문자 구분 으로 처리.
|
|
if (result == -1)
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_check_request: dav_shared_is_uri_ignore_case_by_svcname func fail. svc name[%s]. use default", svc_name);
|
|
|
|
is_uricaseignore = false;
|
|
}
|
|
|
|
// 8. 무인증 정보를 조회하여 해당 정보가 존재하는지 판단한다.
|
|
// - 무인증 정보가 존재할 경우.. 최초 무인증 요청인 경우.. RCDB 정보를 조회하여 redirect 처리 시켜 준다..
|
|
// - 최초 무인증 요청이 아니고.. redirect 처리되어 들어온 요청인 경우... Authorization 정보를 설정하여 opendav 로 전달 처리한다.
|
|
for (i = 0; i < maxanon; i++)
|
|
{
|
|
// 무인증 설정 정보가 없는 경우 그냥 통과...
|
|
if ((g_ar + i)->domain[0] == '\0')
|
|
break;
|
|
|
|
// 2015.7.15 dadamin
|
|
// version 3.5부터 fimngd 의해서 설정된 flag 참조
|
|
// 1 : 삭제
|
|
if ((g_ar + i)->nFlag == 1)
|
|
continue;
|
|
|
|
// 대소문자 구분 여부에 따라.. 무인증 폴더 존재 여부 확인..
|
|
|
|
// URI 대소문자 무시 서비스인 경우
|
|
if (is_uricaseignore == true)
|
|
{
|
|
result = (!strcasecmp(folder_name, (g_ar + i)->uri)
|
|
&& !strncasecmp(svc_name, (g_ar + i)->domain, svc_name_len)
|
|
&& strlen((g_ar + i)->domain) == svc_name_len);
|
|
|
|
}
|
|
else // 양방향 기본 ( URI 대소문자 구분 )
|
|
{
|
|
result = (strcmp(folder_name, (g_ar + i)->uri) == OK
|
|
&& !strncasecmp(svc_name, (g_ar + i)->domain, svc_name_len)
|
|
&& strlen((g_ar + i)->domain) == svc_name_len);
|
|
}
|
|
|
|
// 전달받은 URL 이 무인증 폴더상에 존재하는 경우
|
|
if (result)
|
|
{
|
|
|
|
// 최초 무인증 요청인 경우 301 redirect 처리..
|
|
// redirect 처리된 요청인 경우... Authorization 설정 후 통과 처리.
|
|
|
|
// 이미 redirect 처리되어 들어온 요청인 경우.
|
|
if (is_redirect_request == true)
|
|
{
|
|
//ap_log_error( APLOG_MARK, APLOG_NOTICE, 0, NULL, "dav_shared_ar_check_request: already redirect request. set auth and pass. uri[%s]", uri);
|
|
|
|
// HTTP Header 상에 Authorization Header 정보가 존재하지 않는 경우... 해당 정보 강제로 등록 처리.
|
|
apr_table_setn(r->headers_in, "Authorization", apr_pstrdup(r->pool, "Basic REDIRECTED"));
|
|
return OK;
|
|
}
|
|
else
|
|
{
|
|
// 최초 무인증 확인 요청인 경우
|
|
if (dav_find_location(r, svc_name, uri, is_uricaseignore, true) == OK)
|
|
return HTTP_MOVED_PERMANENTLY;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// 무인증 폴더 정보가 존재하지 않는 경우...
|
|
// 그냥 opendav 로 통과 처리.
|
|
return OK;
|
|
|
|
#endif // __OPENDISK_SOLUTION__
|
|
}
|
|
|
|
// CHG 2012-04-21 huibong
|
|
// 본 함수는 auth.c 에서 인증 관련 여부 확인 처리를 위해 호출되는 함수이지만..
|
|
// 거지 같은 처리 flow 로 구성되어...전면 재수정 처리한다.
|
|
|
|
// 본 함수는 들어온 요청이 무인증 관련 요청인지 확인하고...
|
|
// 무인증 요청인 경우 URL 의 정보를 변경하고.. RedHost 상에 서비스 Name 정보를 전달한다.
|
|
int dav_shared_ar_get_value(request_rec *r)
|
|
{
|
|
|
|
#if defined(__OPENDISK_SOLUTION__) || defined(__OPENDAV_SHARED_NOT_USE)
|
|
return DECLINED;
|
|
#else
|
|
|
|
// 서비스명, uri, 무인증 폴더 정보 저장을 위한 변수
|
|
const char * p1 = NULL;
|
|
char * request_path = NULL;
|
|
|
|
char * svc_name = NULL;
|
|
char * uri = NULL;
|
|
char * folder_name = NULL;
|
|
int svc_name_len = 0;
|
|
int folder_name_len = 0;
|
|
|
|
// 각 서비스별 URI 대소문자 구분 여부 정보를 저장하기 위한 변수. true: URI 대소문자 무시, false: URI 대소문자 구분 (default)
|
|
int result = 0;
|
|
bool is_uricaseignore = false;
|
|
|
|
// loop 처리 관련 변수
|
|
int i;
|
|
|
|
|
|
// 1. 변수값 검사
|
|
if (!g_ar)
|
|
return DECLINED;
|
|
|
|
if (!r)
|
|
return DECLINED;
|
|
|
|
// 2. 무인증은 GET 요청만 허용.
|
|
if (r->method_number != M_GET)
|
|
{
|
|
return DECLINED;
|
|
}
|
|
|
|
// NEW 2012-04-23 huibong
|
|
// - HTTP Header 상에 인증 관련 Authorization 정보가 존재하고, dav_shared_ar_check_request() 함수에서 입력한 "Basic REDIRECTED" 정보가 아닌 경우.. 양방향 인증으로 처리되도록 처리.
|
|
p1 = apr_table_get(r->headers_in, "Authorization");
|
|
if (p1 != NULL)
|
|
{
|
|
if (strcmp(p1, "Basic REDIRECTED") != 0)
|
|
{
|
|
return DECLINED;
|
|
}
|
|
}
|
|
|
|
// 3. URL 추출
|
|
ap_unescape_url(r->unparsed_uri);
|
|
// 공유 메모리에 UTF-8로 저장되어 있기 때문에 변환 필요
|
|
uri = transformUTF8(r, r->unparsed_uri, "dav_shared_ar_get_value");
|
|
|
|
// 3. 요청이 무인증 요청인지 확인한다.
|
|
// - 추가로 무인증 요청인 경우 무인증 정보 확인을 위한 서비스명, 폴더명을 추출한다.
|
|
// 양방향 기본 : /dav/svc1_test/temp1.txt
|
|
// 무인증 redirect 처리 후 : /dav/nctest/SVC1_TEST/temp2.txt ( /dav/ 서비스 Name / 경로명 )
|
|
// 무인증 최초 요청 : /svc1_test/TEMP7.txt
|
|
// 기타 : /a , /ok.html 등등.
|
|
|
|
// 3-1 uri 의 길이값을 확인
|
|
// /로 시작해야 하고.. 뒤에 경로 정보가 들어 있어야 하므로...
|
|
// 최소 형식은 /a/a, /dav 의 4 byte 이상이어야 한다.
|
|
if (strlen(uri) < 4)
|
|
{
|
|
// 무인증 uri 규칙 위배 상황이고.. Authorization 정보도 존재하지 않으므로.. 거부 처리.
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_get_value: uri not valid. length too small [%s]", uri);
|
|
return DECLINED;
|
|
}
|
|
|
|
// 3-2 /dav/ 로 시작해야 함.
|
|
if (strstr(uri, "/dav/") == uri)
|
|
{
|
|
// /dav/ 로 시작하는 uri 인 경우..
|
|
// /dav/ 로 시작하는 부분을 건너뛰고... 다음 문자를 서비스 Name 으로 처리.... 그 다음을 경로로 처리..
|
|
|
|
p1 = uri;
|
|
p1 = p1 + 5; // p1 -> nctest/SVC1_TEST/temp2.txt 형식
|
|
|
|
request_path = strchr(p1, '/'); // request_path -> /SVC1_TEST/temp2.txt 형식
|
|
if (request_path == NULL)
|
|
{
|
|
// 무인증 redirect 처리 규칙 위배 상황
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_get_value: redirect uri format not valid [%s]", uri);
|
|
return DECLINED;
|
|
}
|
|
|
|
// 서비스 Name 정보를 추출..
|
|
svc_name_len = (request_path - p1);
|
|
svc_name = apr_pstrdup(r->pool, p1);
|
|
*(svc_name + svc_name_len) = '\0';
|
|
|
|
// 무인증 폴더 정보를 추출한다.
|
|
// 정상 : /SVC1_TEST/a.txt 형식
|
|
// 오류 : /SVC1_TEST , // , //a.txt
|
|
|
|
request_path = request_path + 1; // request_path -> SVC1_TEST/a.txt 형식
|
|
p1 = strchr(request_path, '/');
|
|
if (p1 == NULL)
|
|
{
|
|
// 무인증 redirect 처리 규칙 위배 상황.. 경로 정보 존재하지 않음.
|
|
//ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_get_value: annoymous uri format not valid [%s]", uri );
|
|
return DECLINED;
|
|
}
|
|
else
|
|
{
|
|
folder_name_len = (p1 - request_path);
|
|
|
|
if (folder_name_len < 1) // 구조가 a/ 구조가 아닌 경우 즉.. //
|
|
{
|
|
// 무인증 요청 규칙 위배이므로 거부 처리.
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_get_value: annoymous folder name length not valid [%s]", uri);
|
|
return DECLINED;
|
|
}
|
|
else
|
|
{
|
|
folder_name = apr_pstrdup(r->pool, request_path);
|
|
*(folder_name + folder_name_len) = '\0'; // folder_name -> SVC1_TEST 형식
|
|
}
|
|
}
|
|
}
|
|
|
|
// 4. 서비스 Name, folder name 정보를 확인하여 추출하지 못한 경우.. 무인증 요청이 아님.
|
|
if (svc_name == NULL || folder_name == NULL)
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_get_value: not valid annoymous request [%s]", uri);
|
|
return DECLINED;
|
|
}
|
|
|
|
// 5. 해당 서비스의 대소문자 무시 여부를 판단한다.
|
|
result = dav_shared_is_uri_ignore_case_by_svcname(svc_name);
|
|
if (result == 1) // URI 대소문자 무시 서비스인 경우
|
|
{
|
|
is_uricaseignore = true;
|
|
}
|
|
else
|
|
{
|
|
// 만약 dav_shared_is_uri_ignore_case 호출시 오류가 발생한 경우.. 양방향 기본은 대소문자 구분 으로 처리.
|
|
if (result == -1)
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ar_get_value: dav_shared_is_uri_ignore_case_by_svcname func fail. svc name[%s]. use default", svc_name);
|
|
|
|
is_uricaseignore = false;
|
|
}
|
|
|
|
|
|
// 6. 무인증 정보를 조회하여 해당 정보가 존재하는지 판단한다.
|
|
for (i = 0; i < maxanon; i++)
|
|
{
|
|
// 무인증 설정 정보가 없는 경우 그냥 통과...
|
|
if ((g_ar + i)->domain[0] == '\0')
|
|
break;
|
|
|
|
// 2015.7.15 dadamin
|
|
// version 3.5부터 fimnd 의해서 설정된 flag 값 참조
|
|
// 1 : 삭제
|
|
if ((g_ar + i)->nFlag == 1)
|
|
continue;
|
|
|
|
// 대소문자 구분 여부에 따라.. 무인증 폴더 존재 여부 확인..
|
|
|
|
// URI 대소문자 무시 서비스인 경우
|
|
if (is_uricaseignore == true)
|
|
{
|
|
result = (!strcasecmp(folder_name, (g_ar + i)->uri)
|
|
&& !strncasecmp(svc_name, (g_ar + i)->domain, svc_name_len)
|
|
&& strlen((g_ar + i)->domain) == svc_name_len);
|
|
|
|
}
|
|
else // 양방향 기본 ( URI 대소문자 구분 )
|
|
{
|
|
result = (strcmp(folder_name, (g_ar + i)->uri) == OK
|
|
&& !strncasecmp(svc_name, (g_ar + i)->domain, svc_name_len)
|
|
&& strlen((g_ar + i)->domain) == svc_name_len);
|
|
}
|
|
|
|
// 전달받은 URL 이 무인증 폴더상에 존재하는 경우
|
|
if (result)
|
|
{
|
|
char * new_uri = NULL;
|
|
|
|
// URI 부분 중 무인증 경로 관련 부분만 변환 처리 여부를 결정한다.
|
|
if (uri == r->unparsed_uri)
|
|
{
|
|
new_uri = transformDBCharacter(r, request_path, "dav_shared_ar_get_value");
|
|
}
|
|
|
|
// iconv 변환 필요가 없거나...변환 실패시... 신규 URL 을 조립.
|
|
if (!new_uri)
|
|
{
|
|
new_uri = apr_pstrcat(r->pool, "/dav/", request_path, NULL);
|
|
}
|
|
else
|
|
{
|
|
new_uri = apr_pstrcat(r->pool, "/dav/", new_uri, NULL);
|
|
}
|
|
|
|
ap_parse_uri(r, new_uri);
|
|
ap_getparents(r->uri);
|
|
|
|
// HTTP RedHost tag 상에는 서비스 Name 정보를 입력 처리한다.
|
|
apr_table_setn(r->headers_in, "RedHost", svc_name);
|
|
|
|
//ap_log_error(APLOG_MARK, APLOG_NOTICE, 0, NULL, "dav_shared_ar_get_value: new_uri [%s], RedHost [%s]", new_uri, svc_name);
|
|
|
|
return OK;
|
|
}
|
|
}
|
|
|
|
return DECLINED;
|
|
|
|
|
|
#endif // __OPENDISK_SOLUTION__
|
|
}
|