Files
interactive/fhs/sh-opendav/share_account.c
2026-08-07 17:38:18 +09:00

450 lines
10 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"
/* for user cache */
static struct shm_mgnt ucah_mgnt = {
NULL, NULL, SHM_UCAH, SHM_UCAH_LOCK, 0, 0
};
struct account_cache *g_ac;
static int maxcache = 0 ;
int dav_initialize_shared_account_cache(dav_repos_server_conf *dsc, server_rec *s, apr_pool_t *p)
{
if (dsc->user_cache <= 0) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, "OPENDAV: initialize_shared_memory: "
"MaxUserCache <= 0 (%d)", dsc->user_cache);
return !OK;
}
maxcache = dsc->user_cache;
/* user cache : calculate shared memory size from user_cache value */
ucah_mgnt.size = (sizeof(struct account_cache) * dsc->user_cache);
g_ac = (struct account_cache *)dav_shared_get_new_memory(&ucah_mgnt, s, p, false);
if (!g_ac) return !OK;
return OK;
}
void dav_cleanup_shared_account_cache()
{
if (ucah_mgnt.shm) {
apr_shm_detach(ucah_mgnt.shm);
}
if (ucah_mgnt.lock) {
apr_global_mutex_destroy(ucah_mgnt.lock);
}
}
struct account_cache * dav_shared_ac_get_by_vol(const char * volume_name)
{
#ifndef __OPENDAV_SHARED_NOT_USE
int i;
if (!g_ac)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ac_get_by_vol:: Account cache NULL. [%s]", volume_name);
return NULL;
}
#define AC_TIMEOUT 300
apr_global_mutex_lock(ucah_mgnt.lock);
for (i = 0; i < maxcache; i++)
{
if ((g_ac + i)->id[0] == '\0')
break;
if (!strcmp((g_ac + i)->svc_id, volume_name))
{
struct account_cache * retval = (g_ac + i);
// 2015.7.15 dadamin
// version 3.5부터 timeout 대신 fimnd 의해서 설정된 flag 값 참조
// 0 : 정상 , 1 : 삭제
if ((g_ac + i)->nFlag)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ac_get_by_vol:: The [%s] service is deleted.", (g_ac + i)->svc_id);
retval = NULL;
}
apr_global_mutex_unlock(ucah_mgnt.lock);
return retval;
}
}
apr_global_mutex_unlock(ucah_mgnt.lock);
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ac_get_by_vol:: The [%s] service not found.", volume_name);
#endif
return NULL;
}
// NEW 2012-04-20 노경민
// dav_shared_ac_get_by_vol() 함수 상의 TIMEOUT 체크 기능으로 인해
// 무인증 관련 서비스의 대소문자 구분/무시 여부 확인 처리시...
// Cache 값 변경이 발생되지 않아... NULL 값이 반환되는 문제 발생..
// 따라서 이를 해결하기 위해 TIMEOUT 비교가 없는 함수를 추가함.
struct account_cache * dav_shared_ac_get_by_vol_not_timeout(const char * volume_name)
{
#ifndef __OPENDAV_SHARED_NOT_USE
int i;
if (!g_ac)
return NULL;
apr_global_mutex_lock(ucah_mgnt.lock);
for (i = 0; i < maxcache; i++)
{
if ((g_ac + i)->id[0] == '\0')
break;
// 2015.7.15 dadamin
// version 3.5부터 timeout 대신 fimnd 의해서 설정된 flag 값 참조
// 0 : 정상 , 1 : 삭제
if ((g_ac + i)->nFlag)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ac_get_by_vol_not_timeout:: The [%s] service is deleted.", (g_ac + i)->svc_id);
continue;
}
if (!strcmp((g_ac + i)->svc_id, volume_name))
{
struct account_cache * retval = (g_ac + i);
apr_global_mutex_unlock(ucah_mgnt.lock);
return retval;
}
}
apr_global_mutex_unlock(ucah_mgnt.lock);
#endif
return NULL;
}
// 2017-03-08 CHG huibong
// - #28349 서비스 해지 처리된 경우 불필요한 로그가 인증시마다 발생, 이를 해결하기 위해 Flow 수정 처리.
//
struct account_cache *dav_shared_ac_get_by_tranid(char *seq)
{
#ifndef __OPENDAV_SHARED_NOT_USE
int i;
if (!g_ac)
return NULL;
apr_global_mutex_lock(ucah_mgnt.lock);
// 2015.7.15 dadamin
// version 3.5부터 timeout 대신 fimnd 의해서 설정된 flag 값 참조
// 0 : 정상 , 1 : 삭제
// 인증 처리 부분이므로 검색 속도는 최대한 빠르게 한다.
for (i = 0; i < maxcache; i++)
{
if ((g_ac + i)->id[0] == '\0')
break;
// 삭제된 서비스는 검색 조건에서 제거
if((g_ac + i)->nFlag)
{
continue;
}
// 서비스 sequece 비교
if(!strcmp((g_ac + i)->tran_id, seq))
{
struct account_cache * retval = (g_ac + i);
apr_global_mutex_unlock(ucah_mgnt.lock);
return retval;
}
}
// 삭제된 서비스 요청을 로깅 처리.
// - 요청량이 많지 않을 것이므로.. 응답이 늦어도 상관 없음.
// - 로깅 처리 후 NULL 반환
//for (i = 0; i < maxcache; i++)
//{
// if ((g_ac + i)->id[0] == '\0')
// break;
//
// // 삭제된 서비스
// if((g_ac + i)->nFlag)
// {
// // 삭제 또는 모르는 요청인 경우.. 전달받은 seq 값이 숫자로 변환되지 않고 요청된 그대로 들어오므로...
// // cache 된 정보와 seq 비교는 할 수 없다.
// // 따라서 그냥 해지된 서비스는 모두 로깅 처리한다.
// ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_ac_get_by_tranid:: service [%s] is deleted.", (g_ac + i)->svc_id);
//
// continue;
// }
//}
apr_global_mutex_unlock(ucah_mgnt.lock);
#endif
return NULL;
}
// NEW 2012-03-20 노경민
// 각 서비스별 uri 에 대한 대소문자 구분, 무시 여부를 반환한다.
// 해당 반환값은 RCDB t_sms_sp_svc_product 테이블 uri_ignore_case 필드의 설정값을 확인하여 다음과 같이 반환처리한다.
// 0 : 대소문자 구분 ( 양방향 Default )
// 1 : 대소문자 무시
// -1 : 오류 발생.
int dav_shared_is_uri_ignore_case(const dav_resource * resource)
{
struct account_cache * ac = NULL;
dav_resource_private *info = NULL;
char *tranid;
if (resource == NULL || resource->info == NULL)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_is_uri_ignore_case: dav_resource NULL.");
return -1;
}
info = resource->info;
tranid = apr_psprintf(resource->pool, "%" APR_INT64_T_FMT "", info->user_id);
ac = dav_shared_ac_get_by_tranid(tranid);
// 해당 서비스 정보를 공유 메모리 상에서 확인하지 못한 경우
if (ac == NULL)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_is_uri_ignore_case: tranid[%s] uri ignore info not found.", tranid);
return -1;
}
return ac->is_ignorecase;
}
int dav_shared_is_uri_ignore_case_by_tranid(char *tranid)
{
struct account_cache * ac = NULL;
ac = dav_shared_ac_get_by_tranid(tranid);
// 해당 서비스 정보를 공유 메모리 상에서 확인하지 못한 경우
if (ac == NULL)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_is_uri_ignore_case_by_tranid: tranid[%s] uri ignore info not found.", tranid);
return -1;
}
return ac->is_ignorecase;
}
int dav_shared_is_uri_ignore_case_by_svcname(const char * svcname)
{
struct account_cache * ac = NULL;
ac = dav_shared_ac_get_by_vol_not_timeout(svcname);
// 해당 서비스 정보를 공유 메모리 상에서 확인하지 못한 경우
if (ac == NULL)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_shared_is_uri_ignore_case_by_svcname: svcname[%s] uri ignore info not found.", svcname);
return -1;
}
return ac->is_ignorecase;
}
static int dav_shared_ac_perform_find(char *haystack, char *__needle, int iscase)
{
char *needle = __needle;
int i, h = strlen(haystack), n = strlen(needle);
do {
// ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: Referer: find: needle %s/%s", needle, __needle);
__needle = needle;
if (h < n) goto next_time;
for (i = 0; i < (h - n + 1); i++) {
if (tolower(*(haystack + i)) == tolower(*needle)) {
#if 0
if (iscase == OK) {
#endif
if (!strncasecmp((haystack + i), needle, n)) {
goto match_n_next;
}
#if 0
}
else {
if (!strncmp((haystack + i), needle, n)) {
goto match_n_next;
}
}
#endif
continue;
match_n_next:
if (i != 0 && *(haystack + i - 1) != '|')
continue;
if (*(haystack + i + n) != '|' && *(haystack + i + n) != '\0')
continue;
return OK;
}
}
//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: Referer: find: done?");
next_time:
needle = strchr(__needle, '.');
// ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: Referer: find: done? needle %x __needle %x", needle, __needle);
if (needle) {
needle++;
if (*needle == '\0') break;
n = strlen(needle);
}
} while (needle);
// ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: Referer: find: ALL done?");
return !OK;
}
#define IS_PERMIT_EMPTY_REFERER(ac) (strlen(ac->mode) > 4 && ac->mode[4] == '1')
int dav_shared_ac_check_referer(struct account_cache *ac, request_rec *r)
{
const char *referer = apr_table_get(r->headers_in, "Referer");
char *pszCopy, *pszUriCopy;
char *p, *p2, *p3, *q;
if ((!referer) || (NULL == referer) || (0 == strlen(referer)))
{
if (IS_PERMIT_EMPTY_REFERER(ac))
{
if (ac->permitted_referer[0] != '\0')
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: empty referer checking: referer is NULL, not permited.");
return !OK;
}
}
return OK;
}
if (ac->permitted_referer[0] == '\0')
return OK;
pszCopy = apr_pstrdup(r->pool, referer);
if (!pszCopy)
return OK;
if ((p = strstr(pszCopy, "://")))
p += 3;
else
p = pszCopy;
p2 = strchr(p, '/');
p3 = strchr(p, ':');
if (p2 == NULL)
{
if (p3 == NULL)
{
if (IS_PERMIT_EMPTY_REFERER(ac))
{
if (ac->permitted_referer[0] != '\0')
;
else
return OK;
}
else
return OK;
}
else
{
q = p3;
*q = '\0';
}
}
else
{
if (p3 == NULL)
q = p2;
else if (p2 < p3)
q = p2;
else
q = p3;
*q = '\0';
}
pszUriCopy = apr_pstrdup(r->pool, r->uri);
q = pszUriCopy;
if ((p2 = strrchr(q, '.')))
q = p2 + 1;
else
q = NULL;
if (ac->permitted_extend[0] != '\0')
{
if (!q)
return OK;
if (dav_shared_ac_perform_find(ac->permitted_extend, q, !OK) == !OK)
return OK;
}
if (ac->permitted_referer[0] != '\0')
{
if (dav_shared_ac_perform_find(ac->permitted_referer, p, OK) == !OK)
{
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: referer: uri %s, extension %s, permitted %s !!!!!"
, p, (ac->permitted_extend[0] != '\0' ? ac->permitted_extend : "NONE"), ac->permitted_referer);
return !OK;
}
}
return OK;
}