2097 lines
57 KiB
C
2097 lines
57 KiB
C
/****************************************************************************
|
|
|
|
mod_dav_pgsql (DASL) for apache 2.X
|
|
CopyRight(C) 2005 SolutionBox Inc. All Rights reserved.
|
|
Author : sean kim (sean@solutionbox.co.kr)
|
|
|
|
$Id: auth.c,v 1.4 2007/03/19 08:43:11 elenoa Exp $
|
|
|
|
Redistribution and use in source and binary forms, with or with out
|
|
modification, are not permitted in outside of SolutionBox Inc.
|
|
|
|
****************************************************************************/
|
|
|
|
#include <ctype.h>
|
|
#include <mcrypt.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 <http_connection.h>
|
|
|
|
#include <apr_strings.h>
|
|
#include <apr_hash.h>
|
|
#include <apr_base64.h>
|
|
|
|
#include "dav_repos.h"
|
|
#include "dbms.h"
|
|
#include "util.h"
|
|
#include "share_common.h"
|
|
#include "share_account.h"
|
|
#include "share_anonymous.h"
|
|
|
|
|
|
// 2018-01-25 huibong 토토지원 과금 IP 확인용 임시 코드 , inet_ntop()
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
|
|
|
|
|
|
#define MaxSizeOfQueryBuffer 1024
|
|
/* Note: the "dav_repos" prefix is mandatory */
|
|
extern module AP_MODULE_DECLARE_DATA dav_repos_module;
|
|
|
|
int dav_auth_user(request_rec *r, apr_off_t content, apr_off_t *permitted);
|
|
|
|
|
|
/* Elenoa 2005.12.28 : SP-Authrization START */
|
|
/* Copy and Modify : ap_get_basic_auth_pw from server/protocol.c */
|
|
|
|
/* Cannot use ap_pbase64decode. remake ap_get_basic_auth_pw */
|
|
static int dav_auth_get_pw_str(request_rec *r, const char **pw)
|
|
{
|
|
const char *auth_line = apr_table_get(r->headers_in,
|
|
(PROXYREQ_PROXY == r->proxyreq)
|
|
? "Proxy-Authorization"
|
|
: "Authorization");
|
|
const char *t;
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_get_pw_str: authline: %s", auth_line);
|
|
#endif
|
|
|
|
if (!(t = ap_auth_type(r)) || strcasecmp(t, "Basic"))
|
|
return DECLINED;
|
|
|
|
if (!ap_auth_name(r)) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR,
|
|
0, NULL, "need AuthName: %s", r->uri);
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
if (!auth_line) {
|
|
ap_note_basic_auth_failure(r);
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
|
|
if (strcasecmp(ap_getword(r->pool, &auth_line, ' '), "Basic")) {
|
|
/* Client tried to authenticate using wrong auth scheme */
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"client used wrong authentication scheme: %s", r->uri);
|
|
ap_note_basic_auth_failure(r);
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
|
|
while (*auth_line == ' ' || *auth_line == '\t') {
|
|
auth_line++;
|
|
}
|
|
|
|
*pw = auth_line;
|
|
|
|
return OK;
|
|
}
|
|
|
|
#ifdef __OPENDAV_DEBUG__
|
|
void binary_dump(char *szBin, int len)
|
|
{
|
|
int i;
|
|
char outbuf[1024];
|
|
outbuf[0] = '\0';
|
|
|
|
for (i = 0; i < len; i++) {
|
|
sprintf(outbuf, "%s %2X", outbuf, (unsigned char)(*((unsigned char *)szBin + i)));
|
|
|
|
if (((i + 1) % 16) == 0) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s", outbuf);
|
|
outbuf[0] = '\0';
|
|
}
|
|
}
|
|
if (strlen(outbuf) > 0) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s", outbuf);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* OLD Authorization */
|
|
static int dav_auth_sp_old(request_rec *r, char *pszPW, int len, struct account_cache *pac)
|
|
{
|
|
char *pszResult = NULL;
|
|
char *pszCUser = NULL;
|
|
char *pszCExpire = NULL;
|
|
char *pszCPW = NULL;
|
|
char *p1, *p2, *p3;
|
|
MCRYPT mcrypt = NULL;
|
|
time_t now = time(0);
|
|
char *pszKey;
|
|
char *pszIV;
|
|
char *pszDBPW;
|
|
|
|
if (!pszPW || !pac)
|
|
return !OK;
|
|
|
|
pszKey = pac->pk;
|
|
pszIV = pac->iv;
|
|
pszDBPW = pac->pass;
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG3("dav_auth_sp_old::pszPW=%s (%d) pszKey=%s",
|
|
pszPW, len, pszKey);
|
|
DBG1("dav_auth_sp_old::pszIV=%s", pszIV);
|
|
#endif
|
|
//apr_global_mutex_lock(db_global_lock);
|
|
mcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, NULL, MCRYPT_CBC, NULL);
|
|
if (mcrypt == MCRYPT_FAILED) {
|
|
#ifdef __OPENDAV_OLDAUTH_LOG__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR,
|
|
0, NULL, "dav_auth_sp_old: mcrypt open failed");
|
|
#endif
|
|
//apr_global_mutex_unlock(db_global_lock);
|
|
return !OK;
|
|
}
|
|
if (mcrypt_generic_init(mcrypt, pszKey, KEY_LENGTH, pszIV) < 0) {
|
|
#ifdef __OPENDAV_OLDAUTH_LOG__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR,
|
|
0, NULL, "dav_auth_sp_old: mcrypt init failed");
|
|
#endif
|
|
//apr_global_mutex_unlock(db_global_lock);
|
|
return !OK;
|
|
}
|
|
if (mdecrypt_generic(mcrypt, pszPW, len) < 0) {
|
|
#ifdef __OPENDAV_OLDAUTH_LOG__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR,
|
|
0, NULL, "dav_auth_sp_old: mdecrypt failed");
|
|
#endif
|
|
//apr_global_mutex_unlock(db_global_lock);
|
|
return !OK;
|
|
}
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_sp_old::decrypted pszPW=%s", pszPW);
|
|
//DBG1("dav_auth_sp_old::TEST %s", get_hashed_filepath("sp"));
|
|
#endif
|
|
|
|
mcrypt_generic_deinit(mcrypt);
|
|
//apr_global_mutex_unlock(db_global_lock);
|
|
|
|
/* Elenoa : 2006. 4. 6 :
|
|
* fix problem '-' char in userid and product name */
|
|
|
|
/*
|
|
pszCUser = ap_getword_nulls_nc (r->pool, &pszPW, '-');
|
|
pszCPW = ap_getword_nulls_nc (r->pool, &pszPW, '-');
|
|
pszCExpire = pszPW;
|
|
*/
|
|
|
|
p1 = strchr(pszPW, '@');
|
|
p2 = strrchr(pszPW, '-');
|
|
|
|
if (!p1 || !p2) {
|
|
return !OK;
|
|
}
|
|
p1++;
|
|
p3 = p2 - 1;
|
|
while (p3 > p1 && *p3 != '-') p3--;
|
|
|
|
if (p3 == p1) {
|
|
#ifdef __OPENDAV_OLDAUTH_LOG__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_old: password format not matched: case 2");
|
|
#endif
|
|
return !OK;
|
|
}
|
|
|
|
pszCUser = apr_pstrndup(r->pool, pszPW, (p3 - pszPW));
|
|
p3++;
|
|
pszCPW = apr_pstrndup(r->pool, p3, (p2 - p3));
|
|
pszCExpire = p2 + 1;
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG2("dav_auth_sp_old::now=%d expire=%s", now, pszCExpire);
|
|
#endif
|
|
if (atoi(pszCExpire) < now) {
|
|
#ifdef __OPENDAV_OLDAUTH_LOG__
|
|
if (atoi(pszCExpire) != 0) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_old: timeout: server %d client %s",
|
|
now, pszCExpire);
|
|
}
|
|
#endif
|
|
|
|
return !OK;
|
|
}
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_sp_old::pszPW %s", pszPW);
|
|
DBG3("dav_auth_sp_old::pszCUser %s pszCPW %s pszCExpire %s",
|
|
pszCUser, pszCPW, pszCExpire);
|
|
#endif
|
|
|
|
pszResult = apr_pstrcat(r->pool, pszCUser, pszDBPW, pszCExpire, NULL);
|
|
|
|
// CHG 2010-08-10 huibong
|
|
// get_hashed_filepath 함수정의 변경에 따른 코드 수정
|
|
char szHashResult[APR_MD5_DIGESTSIZE * 2 + 1];
|
|
if( get_hashed_filepath( pszResult, szHashResult, sizeof(szHashResult) ) == false )
|
|
{
|
|
// Clear array
|
|
memset( szHashResult, 0x00, sizeof(szHashResult));
|
|
|
|
// Write error log
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_auth_sp_old:get_hashed_filepath return false.[%s][%s][%zu]"
|
|
, pszResult, szHashResult, sizeof(szHashResult));
|
|
}
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
//DBG3("dav_auth_sp_old::pszResult=%s,hash=%s,pszCPW=%s", pszResult, get_hashed_filepath(pszResult), pszCPW);
|
|
DBG3("dav_auth_sp_old::pszResult=%s,hash=%s,pszCPW=%s", pszResult, szHashResult, pszCPW);
|
|
#endif
|
|
|
|
//if (strcmp(get_hashed_filepath(pszResult), pszCPW))
|
|
if (strcmp(szHashResult, pszCPW))
|
|
{
|
|
|
|
#ifdef __OPENDAV_OLDAUTH_LOG__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_auth_sp_old: auth string failed: server %s client %s", szHashResult, pszCPW);
|
|
#endif
|
|
|
|
return !OK;
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
//pac->pk, pac->iv, pac->pass
|
|
/* NEW Authorization */
|
|
static int dav_auth_sp_new(request_rec *r, char *pszPW, int len, struct account_cache *pac)
|
|
{
|
|
char *pszResult = NULL;
|
|
char *pszCUser = NULL;
|
|
char *pszCExpire = NULL;
|
|
char *pszCPW = NULL;
|
|
char *p1, *p2, *p3;
|
|
MCRYPT mcrypt = NULL;
|
|
time_t now = time(0);
|
|
time_t csdk_time = 0;
|
|
char hashed_uri[16];
|
|
char hashed_session_dump[33];
|
|
|
|
// CHG 2011-12-01 huibong
|
|
// apr_md5() 함수 형식에 맞도록 변수 타입 수정 처리
|
|
//char hashed_current_uri[16], *escaped_request;
|
|
unsigned char hashed_current_uri[16];
|
|
char *escaped_request;
|
|
|
|
int i;
|
|
char *pszKey;
|
|
char *pszIV;
|
|
char *pszDBPW;
|
|
|
|
//if (!pszPW || !pszKey || !pszIV || !pszDBPW)
|
|
if (!pszPW || !pac)
|
|
return !OK;
|
|
|
|
pszKey = pac->pk;
|
|
pszIV = pac->iv;
|
|
pszDBPW = pac->pass;
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG3("dav_auth_sp_new::pszPW=%s (%d) pszKey=%s",
|
|
pszPW, len, pszKey);
|
|
DBG1("dav_auth_sp_new::pszIV=%s", pszIV);
|
|
#endif
|
|
|
|
/* compare length. (timestamp, session, uri) */
|
|
if (len <= (4 + 16 + 16)) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_new: length too small (< 36)");
|
|
return !OK;
|
|
}
|
|
|
|
/* Elenoa: 2006. 7. 11: Add New Authrization START */
|
|
/* decrypt tea */
|
|
tea_decrypt(pszPW, len);
|
|
#ifdef __OPENDAV_DEBUG__
|
|
binary_dump(pszPW, len);
|
|
#endif
|
|
/* get time */
|
|
csdk_time = (time_t)*((int *)pszPW);
|
|
pszPW += 4;
|
|
|
|
/* compare timestamp (from CSDK) */
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG2("dav_auth_sp_new::now=%d expire(CSDK)=%d", now, csdk_time);
|
|
#endif
|
|
|
|
#define CSDK_TIMEOUT 3600
|
|
|
|
if ((csdk_time + CSDK_TIMEOUT) < now ||
|
|
(csdk_time - CSDK_TIMEOUT) > now) {
|
|
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_new: timeout (csdk): server %d client %d",
|
|
(int)now, (int)csdk_time);
|
|
return !OK;
|
|
}
|
|
|
|
/* get session (hashed) */
|
|
for (i = 0; i < 16; i++) {
|
|
sprintf((hashed_session_dump + (i << 1)), "%02x", *((unsigned char *)(pszPW + i)));
|
|
}
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_sp_new::session %s", hashed_session_dump);
|
|
#endif
|
|
pszPW += 16;
|
|
|
|
/* get uri (hashed) */
|
|
memcpy(hashed_uri, pszPW, 16);
|
|
pszPW += 16;
|
|
|
|
/* compare md5'd file path */
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG2("dav_auth_sp_new::the_request=%s uri=%s", r->the_request, r->uri);
|
|
#endif
|
|
{
|
|
const char *ll = r->the_request;
|
|
|
|
// CHG 2019-08-28 huibong gcc compile warning 수정 (#32780)
|
|
ap_getword_white(r->pool, &ll); // method
|
|
|
|
char *uri = ap_getword_white(r->pool, &ll); // uri
|
|
escaped_request = apr_pstrdup(r->pool, uri);
|
|
}
|
|
ap_unescape_url(escaped_request);
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_sp_new::escaped_request=%s", escaped_request);
|
|
#endif
|
|
apr_md5(hashed_current_uri, (const unsigned char *)escaped_request, strlen(escaped_request));
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG3("dav_auth_sp_new::hashed_uri=%x inputed hash=%x uri=%s",
|
|
*((int *)hashed_current_uri), *((int *)hashed_uri), escaped_request);
|
|
#endif
|
|
|
|
if (memcmp(hashed_current_uri, hashed_uri, 16)) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_new: uri not match: server %s client %s",
|
|
hashed_current_uri, hashed_uri);
|
|
|
|
return !OK;
|
|
}
|
|
|
|
/* before decrypt mcrypt-blowfish, decrypt base64 first. */
|
|
{
|
|
char *decoded;
|
|
int dec_len;
|
|
char *p;
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_sp_new::pszPW=%s", pszPW);
|
|
#ifdef __OPENDAV_DEBUG__
|
|
binary_dump(pszPW, strlen(pszPW));
|
|
#endif
|
|
#endif
|
|
|
|
decoded = (char *) apr_palloc(r->pool, 8 + (dec_len = apr_base64_decode_len(pszPW)));
|
|
memset(decoded, 0, dec_len + 7);
|
|
dec_len = apr_base64_decode(decoded, pszPW);
|
|
|
|
pszPW = decoded;
|
|
len = dec_len;
|
|
|
|
/* skip til ':' char */
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG2("dav_auth_sp_new::before skip pszPW=%s(%d)", pszPW, len);
|
|
#endif
|
|
if ((p = strchr(pszPW, ':'))) {
|
|
p++;
|
|
len -= (p - pszPW); pszPW = p;
|
|
}
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG2("dav_auth_sp_new::before decrypt pszPW=%s(%d)", pszPW, len);
|
|
#endif
|
|
}
|
|
/* Elenoa: 2006. 7. 11: Add New Authrization END */
|
|
|
|
/* decrypt mcrypt-blowfish */
|
|
//apr_global_mutex_lock(db_global_lock);
|
|
mcrypt = mcrypt_module_open(MCRYPT_BLOWFISH, NULL, MCRYPT_CBC, NULL);
|
|
if (mcrypt == MCRYPT_FAILED) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_new: mcrypt open failed");
|
|
//apr_global_mutex_unlock(db_global_lock);
|
|
return !OK;
|
|
}
|
|
if (mcrypt_generic_init(mcrypt, pszKey, KEY_LENGTH, pszIV) < 0) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_new: mcrypt init failed");
|
|
//apr_global_mutex_unlock(db_global_lock);
|
|
return !OK;
|
|
}
|
|
if (mdecrypt_generic(mcrypt, pszPW, len) < 0) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR,
|
|
0, NULL, "dav_auth_sp_new: mdecrypt failed");
|
|
//apr_global_mutex_unlock(db_global_lock);
|
|
return !OK;
|
|
}
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_sp_new::decrypted pszPW=%s", pszPW);
|
|
//DBG1("dav_auth_sp_new::TEST %s", get_hashed_filepath("sp"));
|
|
#endif
|
|
|
|
mcrypt_generic_deinit(mcrypt);
|
|
//apr_global_mutex_unlock(db_global_lock);
|
|
|
|
/* Elenoa : 2006. 4. 6 :
|
|
* fix problem '-' char in userid and product name */
|
|
|
|
/* parse user id, user pass, timestamp */
|
|
p1 = strchr(pszPW, '@');
|
|
p2 = strrchr(pszPW, '-');
|
|
|
|
if (!p1 || !p2) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_new: password format not matched: case 1");
|
|
return !OK;
|
|
}
|
|
|
|
p1++;
|
|
p3 = p2 - 1;
|
|
while (p3 > p1 && *p3 != '-') p3--;
|
|
|
|
if (p3 == p1) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_new: password format not matched: case 2");
|
|
return !OK;
|
|
}
|
|
|
|
pszCUser = apr_pstrndup(r->pool, pszPW, (p3 - pszPW));
|
|
p3++;
|
|
pszCPW = apr_pstrndup(r->pool, p3, (p2 - p3));
|
|
pszCExpire = p2 + 1;
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG2("dav_auth_sp_new::now=%d expire=%s", now, pszCExpire);
|
|
#endif
|
|
|
|
/* compare expire date (from SSDK) */
|
|
if (atoi(pszCExpire) < now) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_sp_new: timeout: server %d client %s",
|
|
(int)now, pszCExpire);
|
|
|
|
return !OK;
|
|
}
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_sp_new::pszPW %s", pszPW);
|
|
DBG3("dav_auth_sp_new::pszCUser %s pszCPW %s pszCExpire %s",
|
|
pszCUser, pszCPW, pszCExpire);
|
|
#endif
|
|
|
|
pszResult = apr_pstrcat(r->pool, pszCUser, pszDBPW, pszCExpire, NULL);
|
|
|
|
// CHG 2010-08-10 huibong
|
|
// get_hashed_filepath 함수 정의 변경에 따른 코드 수정
|
|
char szHashResult[APR_MD5_DIGESTSIZE * 2 + 1];
|
|
if( get_hashed_filepath( pszResult, szHashResult, sizeof(szHashResult) ) == false )
|
|
{
|
|
// Clear array
|
|
memset( szHashResult, 0x00, sizeof(szHashResult));
|
|
|
|
// Write error log
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_auth_sp_new:get_hashed_filepath return false.[%s][%s][%zu]"
|
|
, pszResult, szHashResult, sizeof(szHashResult));
|
|
}
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG3("dav_auth_sp_new::pszResult=%s,hash=%s,pszCPW=%s", pszResult, szHashResult, pszCPW);
|
|
#endif
|
|
|
|
/* compare hashed password */
|
|
if (strcmp(szHashResult, pszCPW))
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_auth_sp_new: auth string failed: server %s client %s"
|
|
, szHashResult, pszCPW);
|
|
|
|
return !OK;
|
|
}
|
|
|
|
/* New Format */
|
|
r->user = apr_pstrcat(r->pool, r->user, "@", hashed_session_dump, NULL);
|
|
|
|
return OK;
|
|
}
|
|
/* Elenoa 2005.12.28 : SP-Authrization END */
|
|
|
|
|
|
static int dav_auth_check_basic_user(request_rec * r, char *pRcvdPasswd, int len, char *pszSafePasswd, struct account_cache *pac)
|
|
{
|
|
/* make user data */
|
|
r->user = apr_pstrcat(r->pool, pac->tran_id, "@", pac->seq, NULL);
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_check_basic_user::DB pass=%s", pac->pass);
|
|
#endif
|
|
|
|
/* DAV-Authrization */
|
|
if (strcmp(pszSafePasswd, pac->pass)) {
|
|
/* Elenoa 2005.12.28 : SP-Authrization START */
|
|
/* login failed */
|
|
char *pRcvdPasswdNew = apr_pcalloc(r->pool, len + 5);
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG2("dav_auth_check_basic_user:: padd IV:%s Key:%s", pac->iv, pac->pk);
|
|
#endif
|
|
|
|
/* copy a new set of inputed password string */
|
|
memcpy(pRcvdPasswdNew, pRcvdPasswd, len);
|
|
*(pRcvdPasswdNew + len) = '\0';
|
|
|
|
if (
|
|
#ifdef __USE_OLD_AUTH__
|
|
dav_auth_sp_old(r, pRcvdPasswdNew, len, pac) != OK
|
|
#else
|
|
(r->method_number == M_PUT &&
|
|
dav_auth_sp_old(r, pRcvdPasswdNew, len, pac) != OK) ||
|
|
r->method_number != M_PUT
|
|
#endif
|
|
) {
|
|
|
|
/* copy a new set of inputed password string */
|
|
memcpy(pRcvdPasswdNew, pRcvdPasswd, len);
|
|
*(pRcvdPasswdNew + len) = '\0';
|
|
|
|
if (dav_auth_sp_new(r, pRcvdPasswdNew, len, pac) != OK) {
|
|
//ap_note_basic_auth_failure(r);
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
|
|
/* Elenoa: 2007. 2. 1: not here */
|
|
#if 0
|
|
/* Elenoa: 2007. 1. 25: Add 'User Authorization' */
|
|
/* Here we check, if register SP's authorization server */
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER C (%d) %s", getpid(), pac->uri);
|
|
#endif
|
|
if (pac->uri[0] != '\0' && (retval = dav_auth_user(r, pac)) != OK) {
|
|
if (retval == HTTP_UNAUTHORIZED) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: user auth failed: (%s:%s)",
|
|
pac->seq, pac->tran_id);
|
|
return HTTP_PRECONDITION_FAILED;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
/* Elenoa 2005.12.28 : SP-Authrization END */
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
static int dav_auth_get_account_cache(request_rec *r, char *szVolumeID, struct account_cache *ac)
|
|
{
|
|
|
|
struct account_cache *pac;
|
|
memset((char *)ac, 0, sizeof(struct account_cache));
|
|
|
|
if ((pac = dav_shared_ac_get_by_vol(szVolumeID))) {
|
|
memcpy(ac, pac, sizeof(struct account_cache));
|
|
return 0;
|
|
}
|
|
|
|
// 201.07.15 dadamin
|
|
// 서비스 정보 없을 시 수행되던 cache 갱신 로직 삭제처리함
|
|
// 공유 메모리 쓰기 단일화(fimngd 수행) 위함
|
|
|
|
return -1;
|
|
}
|
|
|
|
#ifdef __CLOUD_STREAMING__
|
|
// 2012.12.18 dadamin
|
|
// Axissoft StarPlayer 인증 함수
|
|
bool check_starplayer_auth( request_rec * r )
|
|
{
|
|
// header Accept check
|
|
// 2013-08-05 : 해당 헤더 체크 기능 null 문자(값없음)까지 허용, "Accept:" 와 같은 형식
|
|
// 모마일(아이폰, 안드로이폰) 지원 시 해당 헤더 제거 할 수 없으므로
|
|
// 관련 헤더 null 문자(값없음)까지만 허용하기함
|
|
// 이는 Axissoft 측과 협의된 상태임
|
|
// 스타플레이어에서는 ACCEPT정보를 보내지 않으므로 서버변수 accept가 있으면
|
|
// 스타플레이어 외 다른 방식으로 접근한 케이스이므로 차단
|
|
char *acceptstr = NULL;
|
|
acceptstr = (char *)apr_table_get(r->headers_in, "Accept");
|
|
if(acceptstr && strlen(acceptstr) != 0)
|
|
{
|
|
//ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
// "OPENDAV::check_starplayer_auth fail(Accept header field exist).[%s]",r->unparsed_uri);
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV::check_starplayer_auth fail(Accept header field(%s)).[%s]"
|
|
, acceptstr, r->unparsed_uri);
|
|
return false;
|
|
}
|
|
|
|
// HTTP head 요청 경우 : Range, X-Streaming-Checksum 존재하지 않으므로 인증 통과
|
|
if(r->method_number == M_GET && r->header_only)
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV::check_starplayer_auth HEAD request successed.[%s]",r->unparsed_uri);
|
|
return true;
|
|
}
|
|
|
|
// checksum
|
|
//a = range 문자열 예) "bytes=0-1023"
|
|
//b = checksum 예) 387
|
|
unsigned int checksum = 0;
|
|
const char* p = NULL;
|
|
|
|
p = apr_table_get(r->headers_in, "Range");
|
|
if(p == NULL)
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV::check_starplayer_auth fail(Range not found).[%s]"
|
|
, r->unparsed_uri);
|
|
return false;
|
|
}
|
|
|
|
while (*p != 0)
|
|
{
|
|
checksum += *p++;
|
|
}
|
|
|
|
char buf[16];
|
|
int i = 0;
|
|
|
|
while (checksum && i < sizeof(buf))
|
|
{
|
|
char n = checksum & 0xf;
|
|
if (n < 10)
|
|
buf[i++] = n + '0';
|
|
else
|
|
buf[i++] = (n - 10) + 'a';
|
|
checksum >>= 4;
|
|
}
|
|
|
|
p = apr_table_get(r->headers_in, "X-Streaming-Checksum");
|
|
if(p == NULL)
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV::check_starplayer_auth fail(X-Streaming-Checksum not found).[%s]"
|
|
, r->unparsed_uri);
|
|
return false;
|
|
}
|
|
while (i && p)
|
|
{
|
|
if (buf[--i] != *p++)
|
|
return false;
|
|
}
|
|
|
|
return (*p == 0 && i == 0);
|
|
}
|
|
|
|
int check_cloud_streaming_auth(request_rec * r)
|
|
{
|
|
const char * userAgent = NULL;
|
|
|
|
// 2012.12.18 dadamin
|
|
// Axissoft StarPlayer 인증을 처리 추가(양방향은 무인증 처리함)
|
|
userAgent = apr_table_get( r->headers_in, "User-Agent");
|
|
if(userAgent != NULL && strcmp(userAgent, "StarPlayer/1.0") == 0)
|
|
{
|
|
// Axissoft StarPlayer 인증
|
|
if( check_starplayer_auth(r) == false)
|
|
{
|
|
// Axissoft StarPlayer 인증 실패
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV::check_starplayer_auth fail.[%s]",r->unparsed_uri);
|
|
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
else
|
|
{
|
|
// 무인증 처리를 위하여 서비스 name 설정
|
|
const char * xstreamdomain = NULL;
|
|
xstreamdomain = apr_table_get( r->headers_in, "X-Streaming-Domain");
|
|
|
|
if( xstreamdomain != NULL )
|
|
{
|
|
const char * p1 = NULL;
|
|
char * svc_name = NULL;
|
|
int svc_name_len = 0;
|
|
|
|
p1 = strchr( xstreamdomain, '.' );
|
|
|
|
if( p1 != NULL )
|
|
{
|
|
// 서비스 name 정보로 사용한다.
|
|
svc_name_len = (p1 - xstreamdomain);
|
|
|
|
svc_name = apr_pstrdup(r->pool, xstreamdomain);
|
|
*( svc_name + svc_name_len ) = '\0';
|
|
|
|
if(svc_name == NULL || strlen(svc_name) == 0)
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV::check_cloud_streaming_auth: svc_name of X-Streaming-Domain is NULL.[%s][%s]",
|
|
xstreamdomain, r->unparsed_uri);
|
|
}
|
|
else
|
|
{
|
|
apr_table_setn(r->headers_in, "RedHost", svc_name );
|
|
|
|
// 2013.01.23 dadamin
|
|
// redirect된 경우에 대한 처리
|
|
// uri 규칙 : /dav/서비스명/파일path
|
|
// 이후 로직에서 정상 처리를 위해서 서비스명이 제거되어야함
|
|
ap_unescape_url( r->unparsed_uri );
|
|
if (strstr(r->unparsed_uri , "/dav/") == r->unparsed_uri)
|
|
{
|
|
if (strstr((r->unparsed_uri+5) , svc_name) == (r->unparsed_uri +5))
|
|
{
|
|
char * new_uri = NULL;
|
|
new_uri = r->unparsed_uri+ 5 + strlen(svc_name);
|
|
new_uri = apr_pstrcat(r->pool, "/dav", new_uri, NULL);
|
|
ap_parse_uri( r, new_uri );
|
|
ap_getparents( r->uri );
|
|
}
|
|
}
|
|
//is_anonymous = true;
|
|
return HTTP_NON_AUTHORITATIVE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//is_anonymous = false;
|
|
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV::check_cloud_streaming_auth: X-Streaming-Domain format is wrong [%s] [%s]",
|
|
xstreamdomain, r->unparsed_uri );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//is_anonymous = false;
|
|
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV::check_cloud_streaming_auth: X-Streaming-Domain not found [%s]",
|
|
r->unparsed_uri );
|
|
}
|
|
}
|
|
}
|
|
|
|
return HTTP_OK;
|
|
}
|
|
|
|
#endif // __CLOUD_STREAMING__
|
|
|
|
int dav_auth_authenticate(request_rec * r)
|
|
{
|
|
char *pszSafeUser = NULL;
|
|
char *pRcvdPasswd = NULL;
|
|
char *pszSafePasswd = NULL;
|
|
acct_info stAi;
|
|
int len, result;
|
|
struct account_cache ac;
|
|
apr_status_t rv;
|
|
//int is_user_auth = FALSE, is_band_ctrl = FALSE;
|
|
bool is_anonymous = false;
|
|
|
|
#ifdef __CLOUD_STREAMING__
|
|
int a = check_cloud_streaming_auth(r) ;
|
|
switch (a)
|
|
{
|
|
case HTTP_UNAUTHORIZED:
|
|
is_anonymous = false;
|
|
return HTTP_UNAUTHORIZED;
|
|
break;
|
|
case HTTP_NON_AUTHORITATIVE:
|
|
is_anonymous = true;
|
|
break;
|
|
default:
|
|
is_anonymous = false;
|
|
break;
|
|
}
|
|
#endif // __CLOUD_STREAMING__
|
|
|
|
// 2013.01.15 dadmain
|
|
// Axissoft StarPlayer 인증 실패 되어도 해당 요청이 무인증 디렉토리 경우
|
|
// 인증 처리 되어야 하기 때문에 기존 dav_shared_ar_get_value 함수 호출 될 수 있게 한다.
|
|
/* First, check anonymous */
|
|
if (is_anonymous == true || dav_shared_ar_get_value(r) == OK ) {
|
|
const char *domain;
|
|
char *p;
|
|
char szDomain[1024];
|
|
//int len;
|
|
|
|
#define ANONYMOUS_MD5 "246e939eeea2158750a7b68d10dbbf3f"
|
|
#define ANONYMOUS_AUTH_MD5 "ANONYMOUSCONNECTEDTHROUGHBROWSER"
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG0("dav_auth_authenticate: anonymous try to pass");
|
|
#endif
|
|
|
|
if (!(domain = apr_table_get(r->headers_in, "RedHost")))
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: anonymous RedHost Not Found. [%s]", r->unparsed_uri);
|
|
return DECLINED;
|
|
}
|
|
|
|
p = strchr(domain, '.');
|
|
len = (p ? p - domain : strlen(domain));
|
|
|
|
strncpy(szDomain, domain, len);
|
|
#if 0 // add by pizon
|
|
if (len > 1023) len = 1023
|
|
#endif
|
|
szDomain[len] = '\0';
|
|
|
|
// 2012-04-04 : dadamin
|
|
// dav_auth_get_account_cache < 0 경우 데이터베이스 에러이며, 에러는 503을 리턴 한다.
|
|
result = dav_auth_get_account_cache(r, szDomain, &ac);
|
|
if (result == 0 ) {
|
|
r->user = apr_pstrcat(r->pool, ac.tran_id, "@", ac.seq, "@", ANONYMOUS_AUTH_MD5, NULL);
|
|
|
|
if (dav_shared_ac_check_referer(&ac, r) != OK) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV: Referer Check Done, not permited");
|
|
return HTTP_BAD_REQUEST;
|
|
}
|
|
}
|
|
else if ( result < 0 )
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV::dav_auth_authenticate Error(ANONYMOUSCONNECTED) result[%s:%d]",szDomain, result);
|
|
return ( result == -2 ? HTTP_SERVICE_UNAVAILABLE : HTTP_BAD_REQUEST );
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
if ((rv = dav_auth_get_pw_str(r, (const char **) &pRcvdPasswd)) != OK) {
|
|
#if 0
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_authenticate: dav_auth_get_pw_str: failed");
|
|
#endif
|
|
return rv;
|
|
}
|
|
|
|
/* From here, remained process start */
|
|
/* decode base64 encoding */
|
|
{
|
|
char *decoded, *temp;
|
|
decoded =
|
|
(char *) apr_palloc(r->pool, 8 +
|
|
(len = apr_base64_decode_len(pRcvdPasswd)));
|
|
memset(decoded, 0, len + 7);
|
|
len = apr_base64_decode(decoded, pRcvdPasswd);
|
|
*(decoded + len) = '\0';
|
|
temp = decoded;
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_authenticate: decoded: %s", decoded);
|
|
#endif
|
|
r->user = ap_getword_nulls(r->pool, (const char **)&temp, ':');
|
|
r->ap_auth_type = "Basic";
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG2("dav_auth_authenticate: decoded split: %s, %s", r->user, temp);
|
|
#endif
|
|
pRcvdPasswd = temp; len = len - (strlen(r->user) + 1);
|
|
}
|
|
|
|
/* check validate id and password */
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_authenticate: CHECK POINT #1 %s", r->user);
|
|
#endif
|
|
pszSafeUser = apr_palloc(r->pool, 1 + strlen(r->user));
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG0("dav_auth_authenticate: CHECK POINT #2");
|
|
#endif
|
|
pszSafePasswd = apr_palloc(r->pool, 1 + strlen(pRcvdPasswd));
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG0("dav_auth_authenticate: CHECK POINT #3");
|
|
DBG1("dav_auth_authenticate::r->user = %s", r->user);
|
|
DBG2("dav_auth_authenticate::pRcvdPasswd = %s (%d)", pRcvdPasswd, len);
|
|
#ifdef __OPENDAV_DEBUG__
|
|
binary_dump(pRcvdPasswd, len);
|
|
#endif
|
|
#endif
|
|
check_string(pszSafeUser, r->user, strlen(r->user));
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_authenticate::pszSafeUser = %s", pszSafeUser);
|
|
#endif
|
|
check_string(pszSafePasswd, pRcvdPasswd, strlen(pRcvdPasswd));
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_authenticate::pszSafepasswd = %s", pszSafePasswd);
|
|
#endif
|
|
rv = at_split(pszSafeUser, &stAi);
|
|
//DBG1("dav_auth_authenticate::1st at_split = %d", res);
|
|
if (rv == -1) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_authenticate: at_split fail (%s)", r->user);
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
} else if (rv == -2) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_authenticate: user id format not match (%s)", r->user);
|
|
ap_note_basic_auth_failure(r);
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG1("dav_auth_authenticate::stAi.szVolumeID = %s", stAi.szVolumeID);
|
|
DBG1("dav_auth_authenticate::stAi.szUserID = %s", stAi.szUserID);
|
|
#endif
|
|
|
|
// 2012-04-04 : dadamin
|
|
// dav_auth_get_account_cache < 0 경우 데이터베이스 에러이며, 에러는 503을 리턴 한다.
|
|
/* check cached data */
|
|
result = dav_auth_get_account_cache(r, stAi.szVolumeID, &ac);
|
|
if (result < 0 )
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "OPENDAV::dav_auth_authenticate Error(Cache Check) result[%d]", result);
|
|
|
|
return (result == -2 ? HTTP_SERVICE_UNAVAILABLE : HTTP_BAD_REQUEST);
|
|
}
|
|
|
|
if ( strlen(ac.tran_id) == 0 )
|
|
{
|
|
ap_note_basic_auth_failure(r);
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
rv = dav_auth_check_basic_user(r, pRcvdPasswd, len, pszSafePasswd, &ac);
|
|
|
|
|
|
if (rv != OK) {
|
|
ap_note_basic_auth_failure(r);
|
|
return rv;
|
|
}
|
|
|
|
/* write to cache */
|
|
//dav_shared_ac_add(&ac);
|
|
|
|
return OK;
|
|
}
|
|
|
|
|
|
int dav_auth_authorization(request_rec * r)
|
|
{
|
|
char *user = r->user;
|
|
int m = r->method_number;
|
|
|
|
//apr_array_header_t *reqs_arr = (apr_array_header_t *) ap_requires(r);
|
|
apr_array_header_t *reqs_arr =
|
|
#if AP_SERVER_MAJORVERSION_NUMBER > 2 || AP_SERVER_MINORVERSION_NUMBER >= 3
|
|
NULL;
|
|
#else // 2.2.x
|
|
ap_requires(r);
|
|
#endif // 2.3 over
|
|
|
|
require_line *reqs = reqs_arr ? (require_line *) reqs_arr->elts : NULL;
|
|
|
|
register int x;
|
|
const char *t;
|
|
char *w;
|
|
|
|
#ifdef __OPENDAV_DEBUG_AUTH__
|
|
DBG0("dav_auth_authorization: enter");
|
|
#endif
|
|
|
|
// 2012.04.23 dadamin : 중복 처리 로직 삭제 처리
|
|
// /dav 인증 시 dav_auth_authenticat -> dav_auth_authorization 호출되며,
|
|
// dav_shared_ar_get_value함수 경우 dav_auth_authenticat 호출하여 처리함
|
|
//if (dav_shared_ar_get_value(r) == OK)
|
|
// return OK;
|
|
|
|
if (!reqs_arr) {
|
|
return DECLINED;
|
|
}
|
|
|
|
for (x = 0; x < reqs_arr->nelts; x++) {
|
|
|
|
if (!(reqs[x].method_mask & (1 << m)))
|
|
continue;
|
|
|
|
t = reqs[x].requirement;
|
|
w = ap_getword(r->pool, &t, ' ');
|
|
|
|
if (!strcmp(w, "valid-user")) {
|
|
return OK;
|
|
}
|
|
|
|
if (!strcmp(w, "user")) {
|
|
while (t[0]) {
|
|
w = ap_getword_conf(r->pool, &t);
|
|
if (!strcmp(user, w)) {
|
|
return OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return DECLINED;
|
|
}
|
|
|
|
|
|
/* Elenoa: 2007. 2. 2: dav_auth_user serial */
|
|
|
|
#define RECEIVE_CHUNK 1024
|
|
#define RECEIVE_RESERVED 5
|
|
|
|
static char *dav_auth_user_socket_recv(apr_pool_t *pool, apr_socket_t *sock, char *pszReceive)
|
|
{
|
|
char *pszTemp;
|
|
char szReceive[RECEIVE_CHUNK + RECEIVE_RESERVED];
|
|
apr_size_t bytes_read = RECEIVE_CHUNK;
|
|
apr_status_t rv;
|
|
char ebuf[128];
|
|
|
|
rv = apr_socket_recv(sock, szReceive, &bytes_read);
|
|
if (rv != APR_SUCCESS) {
|
|
apr_socket_close(sock);
|
|
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_user_socket_recv: failure to recv message: %s",
|
|
apr_strerror(rv, ebuf, sizeof ebuf));
|
|
return NULL;
|
|
}
|
|
szReceive[bytes_read] = '\0';
|
|
|
|
if (pszReceive == NULL) {
|
|
pszTemp = apr_pstrdup(pool, szReceive);
|
|
} else {
|
|
pszTemp = apr_pstrcat(pool, pszReceive, szReceive, NULL);
|
|
}
|
|
return pszTemp;
|
|
}
|
|
|
|
|
|
#define CONTENT_LENGTH "Content-Length"
|
|
#define TRANSFER_CHUNKED "Transfer-Encoding: chunked"
|
|
|
|
static int dav_auth_user_body_type(char *pszReceive)
|
|
{
|
|
char *p, *r;
|
|
|
|
p = pszReceive;
|
|
while( (r = strstr(p, "\r\n")) )
|
|
{
|
|
// CHG 2012-04-21 huibong
|
|
// 포인터 위치 이동 관련 업무 flow 와 맞지 않아.. 수정 처리함.
|
|
//r += 2; p++;
|
|
|
|
r += 2;
|
|
p = r;
|
|
|
|
if( !strncasecmp(r, CONTENT_LENGTH, strlen(CONTENT_LENGTH)))
|
|
{
|
|
return 0;
|
|
}
|
|
if( !strncasecmp(r, TRANSFER_CHUNKED, strlen(TRANSFER_CHUNKED)))
|
|
{
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define VALIDATED_STRING "1000"
|
|
#define VALIDATED_FIELD "code"
|
|
#define PERMIT_FIELD "permitted_size"
|
|
#ifdef __CLASSIFIED_TRAFFIC_MANAGE__
|
|
#define CLASSIFIER "classified"
|
|
#endif
|
|
static int dav_auth_user_validate(request_rec *r, char *pszReceive, int is_chunked, apr_off_t *permitted)
|
|
{
|
|
char *p, *p2, *p3, *p4;
|
|
int retval = -1;
|
|
#ifdef __CLASSIFIED_TRAFFIC_MANAGE__
|
|
int classified = -1;
|
|
#endif // __CLASSIFIED_TRAFFIC_MANAGE__
|
|
|
|
p = pszReceive;
|
|
if ((p2 = strstr(p, "\r\n\r\n"))) {
|
|
p2 += 4;
|
|
if (is_chunked) {
|
|
/* we must skip one line more */
|
|
p = p2;
|
|
p2 = strstr(p, "\r\n");
|
|
if (!p2) return -1;
|
|
p2 += 2;
|
|
}
|
|
|
|
while (1) {
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER V (%d) %s", getpid(), p2);
|
|
#endif
|
|
|
|
if (!strncasecmp(p2, VALIDATED_FIELD, strlen(VALIDATED_FIELD)) &&
|
|
*(p2 + strlen(VALIDATED_FIELD)) == '|') {
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER V2 (%d) %s", getpid(), (p2 + strlen(VALIDATED_FIELD) + 1));
|
|
#endif
|
|
retval = 0;
|
|
|
|
if (!strncasecmp((p2 + strlen(VALIDATED_FIELD) + 1),
|
|
VALIDATED_STRING, strlen(VALIDATED_STRING))) {
|
|
retval = 1;
|
|
}
|
|
}
|
|
if (!strncasecmp(p2, PERMIT_FIELD, strlen(PERMIT_FIELD)) &&
|
|
*(p2 + strlen(PERMIT_FIELD)) == '|') {
|
|
|
|
if (permitted) {
|
|
*permitted = atoll((p2 + strlen(PERMIT_FIELD) + 1));
|
|
}
|
|
}
|
|
|
|
#ifdef __CLASSIFIED_TRAFFIC_MANAGE__
|
|
if (!strncasecmp(p2, CLASSIFIER, strlen(CLASSIFIER)) &&
|
|
*(p2 + strlen(CLASSIFIER)) == '|') {
|
|
|
|
if (classified == -1) {
|
|
classified = atoi((p2 + strlen(CLASSIFIER) + 1));
|
|
}
|
|
}
|
|
#endif
|
|
|
|
p3 = strstr(p2, "\r\n");
|
|
p4 = strchr(p2, '\n');
|
|
|
|
if (p3 == NULL && p4 == NULL)
|
|
break;
|
|
|
|
if (p3 != NULL && (p4 == NULL || (p3 < p4)))
|
|
p2 = p3 + 2;
|
|
|
|
if (p4 != NULL && (p3 == NULL || (p4 < p3)))
|
|
p2 = p4 + 1;
|
|
}
|
|
}
|
|
|
|
#ifdef __CLASSIFIED_TRAFFIC_MANAGE__
|
|
if (classified > -1) {
|
|
acct_info ai;
|
|
int rv = at_split(r->user, &ai);
|
|
|
|
if (rv == 1) {
|
|
sprintf(ai.szTCClassID, "%d", classified);
|
|
|
|
r->user = apr_pstrcat(r->pool, ai.szVolumeID, ".",
|
|
ai.szTCClassID, "@", ai.szUserID, "@",
|
|
ai.szSessionID, NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
static int dav_auth_parse_byterange(char *range, apr_off_t clength,
|
|
apr_off_t *start, apr_off_t *end)
|
|
{
|
|
char *dash = strchr(range, '-');
|
|
char *errp;
|
|
apr_off_t number;
|
|
|
|
if (!dash) {
|
|
return 0;
|
|
}
|
|
|
|
if ((dash == range)) {
|
|
/* In the form "-5" */
|
|
if (apr_strtoff(&number, dash+1, &errp, 10) || *errp) {
|
|
return 0;
|
|
}
|
|
*start = clength - number;
|
|
*end = clength - 1;
|
|
}
|
|
else {
|
|
*dash++ = '\0';
|
|
if (apr_strtoff(&number, range, &errp, 10) || *errp) {
|
|
return 0;
|
|
}
|
|
*start = number;
|
|
if (*dash) {
|
|
if (apr_strtoff(&number, dash, &errp, 10) || *errp) {
|
|
return 0;
|
|
}
|
|
*end = number;
|
|
}
|
|
else { /* "5-" */
|
|
*end = clength - 1;
|
|
}
|
|
}
|
|
|
|
if (*start < 0) {
|
|
*start = 0;
|
|
}
|
|
|
|
if (*end >= clength) {
|
|
*end = clength - 1;
|
|
}
|
|
|
|
if (*start > *end) {
|
|
return -1;
|
|
}
|
|
|
|
return (*start > 0 || *end < clength);
|
|
}
|
|
|
|
|
|
static int dav_auth_parse_range(char *range, apr_off_t total, apr_off_t *req_be_sent, apr_off_t *start)
|
|
{
|
|
apr_off_t end = 0;
|
|
int retval;
|
|
|
|
*req_be_sent = 0;
|
|
*start = 0;
|
|
|
|
if (!range || strncasecmp(range, "bytes=", 6)) {
|
|
return 0;
|
|
}
|
|
|
|
range = range + 6;
|
|
|
|
retval = dav_auth_parse_byterange(range, total, start, &end);
|
|
*req_be_sent = (end - *start + 1);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
static void dav_auth_user_set_permitted(request_rec *r, apr_off_t start, apr_off_t permitted)
|
|
{
|
|
apr_table_unset(r->headers_in, "Range");
|
|
apr_table_setn(r->headers_in, "Range",
|
|
apr_psprintf(r->pool, "bytes=%" APR_OFF_T_FMT "-%" APR_OFF_T_FMT,
|
|
start, (start + permitted - 1)));
|
|
}
|
|
|
|
/* Elenoa: 2007. 1. 25: Add 'User Authorization' */
|
|
int dav_auth_user_start(dav_resource_private *info)
|
|
{
|
|
apr_off_t req_be_sent, permitted, start;
|
|
char *range;
|
|
int retval;
|
|
|
|
if (!info->db_r || !info->db_r->r)
|
|
return !OK;
|
|
|
|
range = (char *)apr_table_get(info->db_r->r->headers_in, "Range");
|
|
range = apr_pstrdup(info->db_r->r->pool, range);
|
|
dav_auth_parse_range(range, info->finfo.size, &req_be_sent, &start);
|
|
if( req_be_sent == 0 )
|
|
req_be_sent = info->finfo.size;
|
|
|
|
retval = dav_auth_user(info->db_r->r, req_be_sent, &permitted);
|
|
|
|
if( retval != OK || permitted < 0 )
|
|
{
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "dav_auth_user_start: checked %s, permitted_size %" APR_OFF_T_FMT", FAILED!", retval == OK ? "OK" : "FAILED", permitted );
|
|
|
|
return (permitted < 0 ? HTTP_UNAUTHORIZED : retval);
|
|
}
|
|
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER PERMIT (%d) %" APR_OFF_T_FMT" /%" APR_OFF_T_FMT "", getpid(), permitted, req_be_sent);
|
|
#endif
|
|
|
|
if (permitted > 0 && req_be_sent > permitted)
|
|
{
|
|
dav_auth_user_set_permitted(info->db_r->r, start, permitted);
|
|
}
|
|
|
|
return OK;
|
|
}
|
|
|
|
//2012.03.07 : 상위 모듈에서 사용하고 있는 logio_config_t 값을 참조하기 위한 선언
|
|
module AP_MODULE_DECLARE_DATA logio_module;
|
|
typedef struct __dav_logio_config_t {
|
|
apr_off_t bytes_in;
|
|
apr_off_t bytes_out;
|
|
} dav_logio_config_t;
|
|
|
|
void dav_auth_user_end(dav_resource_private *info)
|
|
{
|
|
if( !info->db_r || !info->db_r->r )
|
|
return;
|
|
|
|
// mod_logio.so의 전송량 참조 : 주의 필요 - access_log 출력 후 관련 값은 초기화됨
|
|
dav_logio_config_t *cf = ap_get_module_config(info->db_r->r->connection->conn_config, &logio_module);
|
|
|
|
const char *cp = NULL;
|
|
cp = apr_table_get(info->db_r->r->headers_out, "Content-Length");
|
|
apr_int64_t clen = apr_atoi64(cp);
|
|
|
|
if (cf->bytes_out > 0)
|
|
{
|
|
// 2015.07.07 : dadamin
|
|
// 헤더가 포함된 값이므로 Content-Length 큰 경우 Content-Length 보냄
|
|
if (cf->bytes_out < clen)
|
|
dav_auth_user(info->db_r->r, cf->bytes_out, NULL);
|
|
else
|
|
dav_auth_user(info->db_r->r, clen, NULL);
|
|
}
|
|
else
|
|
dav_auth_user(info->db_r->r, info->db_r->r->bytes_sent, NULL);
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
static const char c2x_table[] = "0123456789ABCDEF";
|
|
|
|
static APR_INLINE unsigned char *c2x(unsigned what, unsigned char prefix, unsigned char *where)
|
|
{
|
|
#if APR_CHARSET_EBCDIC
|
|
what = apr_xlate_conv_byte(ap_hdrs_to_ascii, (unsigned char)what);
|
|
#endif /*APR_CHARSET_EBCDIC*/
|
|
|
|
*where++ = prefix;
|
|
*where++ = c2x_table[what >> 4];
|
|
*where++ = c2x_table[what & 0xf];
|
|
|
|
return where;
|
|
}
|
|
|
|
static char *dav_escape(apr_pool_t *p, const char *path)
|
|
{
|
|
char *copy = apr_palloc(p, 3 * strlen(path) + 3);
|
|
const unsigned char *s = (const unsigned char *)path;
|
|
unsigned char *d = (unsigned char *)copy;
|
|
unsigned c;
|
|
|
|
while( (c = *s) )
|
|
{
|
|
if( !isalpha(c) && !isdigit(c) )
|
|
{
|
|
d = c2x(c, '%', d);
|
|
}
|
|
else
|
|
{
|
|
(*d) = c;
|
|
d++;
|
|
}
|
|
++s;
|
|
}
|
|
|
|
*d = '\0';
|
|
return copy;
|
|
}
|
|
|
|
#ifdef __OPENDAV_USER_AUTH_GET
|
|
#define AUTH_USER_HEADER \
|
|
"GET %s?session_id=%s HTTP/1.1\r\n" \
|
|
"Host: %s:%d\r\n" \
|
|
"User-Agent: Opendav-%s\r\n" \
|
|
"\r\n"
|
|
#else
|
|
#define AUTH_USER_HEADER \
|
|
"POST %s HTTP/1.1\r\n" \
|
|
"Host: %s:%d\r\n" \
|
|
"Content-Type: application/x-www-form-urlencoded\r\n" \
|
|
"User-Agent: Opendav-%s\r\n" \
|
|
"Connection: Keep-Alive\r\n" \
|
|
"Content-Length: %d\r\n" \
|
|
"\r\n" \
|
|
"%s"
|
|
#endif
|
|
|
|
#define AUTH_USER_BODY_START \
|
|
"session_id=%s&" \
|
|
"uri=%s&" \
|
|
"ip=%s&" \
|
|
"req_size=%" APR_OFF_T_FMT ""
|
|
|
|
// 2017-11-03 CHG huibong (revision 1426, ir #31497)
|
|
// - 토토디스크 측에서 BILL 정보에 request_time, end_time 항목 추가를 요청하여 기능 추가
|
|
// - 현재는 일반 고객은 없지만 향후 발생될 수 있는 신규 고객에도 동일하게 제공
|
|
#define AUTH_USER_BODY_END \
|
|
"session_id=%s&" \
|
|
"uri=%s&" \
|
|
"ip=%s&" \
|
|
"sent_size=%" APR_OFF_T_FMT "" \
|
|
"&request_time=%" APR_TIME_T_FMT "" \
|
|
"&end_time=%" APR_TIME_T_FMT ""
|
|
|
|
#define AUTH_USER_BODY_REFERER \
|
|
"&referer=%s"
|
|
|
|
#define AUTH_USER_BODY_TIMESLICE \
|
|
"&time_%d=%" APR_UINT64_T_FMT ""
|
|
|
|
// 소프트 라인 업로드 파일 싱크 및 다운로드 과금 처리를 위한 필요한 KEY 값 정의
|
|
/// 2013-06-25 : SDK확장 정보(헤더에 SB_ExtSession) 추가로 고객사에서 구분할 수 있으므로 해당 값 정의 필요 없음
|
|
#ifdef __USE_AUTH_SOFTLINE_ONLY__
|
|
#define BILL_DOWNLOAD
|
|
#define BILL_UPLOAD
|
|
|
|
// 업로드 정보 전송관련 time out
|
|
#define BILL_UPLOAD_END_SEND_TIMEOUT 5 // sec
|
|
#define BILL_UPLOAD_END_RECV_TIMEOUT 1 // sec
|
|
|
|
#define BILL_UPLOAD_END \
|
|
"session_id=%s&" \
|
|
"uri=%s&" \
|
|
"ip=%s&" \
|
|
"file_size=%" APR_OFF_T_FMT ""
|
|
#endif // __USE_AUTH_SOFTLINE_ONLY__
|
|
|
|
/*
|
|
#define STRICTLY_AUTH_CODE "100"
|
|
#define IS_STRICTLY_AUTH(ac) \
|
|
(!strncmp(ac->mode, STRICTLY_AUTH_CODE, strlen(STRICTLY_AUTH_CODE)))
|
|
*/
|
|
|
|
#define IS_STRICTLY_AUTH(ac) (ac->mode[0] == '1')
|
|
#define IS_PERMIT_ANONYMOUS(ac) (ac->mode[1] == '0')
|
|
#define IS_PERMIT_DAV_AUTH(ac) (ac->mode[2] == '0')
|
|
#define IS_STRICTLY_ANONYMOUS(ac) (strlen(ac->mode) > 3 && ac->mode[3] == '1')
|
|
#define IS_PERMIT_EMPTY_REFERER(ac) (strlen(ac->mode) > 4 && ac->mode[4] == '1') /* using in "share.c" by pizon */
|
|
|
|
#define AU_PORT (permitted ? ac->auth_port : ac->bill_port)
|
|
#define AU_URI (permitted ? ac->auth_uri : ac->bill_uri)
|
|
#define AU_ADDR (permitted ? ac->auth_addr : ac->bill_addr)
|
|
#define AU_TIMEOUT (permitted ? ac->auth_timeout : ac->bill_timeout)
|
|
|
|
/*
|
|
** r [in] request 정보를 저장한 request_rec 객체에 대한 포인터
|
|
** content [in] 전송 요청 또는 실제 전송한 content size 정보
|
|
** permitted [out] 허용 여부 결과값을 저장할 포인터
|
|
** AUTH 요청인 경우 해당 객체는 NULL 아니지만, BILL 요청인 경우 NULL
|
|
*/
|
|
int dav_auth_user(request_rec *r, apr_off_t content, apr_off_t *permitted)
|
|
{
|
|
acct_info ai;
|
|
apr_status_t rv;
|
|
apr_socket_t *sock;
|
|
apr_sockaddr_t *sa;
|
|
char ebuf[128]; //, buf[120];
|
|
char *pszMessage
|
|
#ifndef __OPENDAV_USER_AUTH_GET
|
|
, *pszBody, *uri
|
|
#endif
|
|
;
|
|
apr_size_t bytes_send;
|
|
struct account_cache *ac;
|
|
const char *referer = apr_table_get(r->headers_in, "Referer");
|
|
|
|
char *pszReceive = NULL;
|
|
int is_chunked = 0, is_code;
|
|
|
|
// 2017-11-03 CHG huibong (revision 1426, ir #31497)
|
|
// - httpd version 별 request_rec 의 client ip 항목이 서로 달라 변수 처리.
|
|
const char *pszClientIP = NULL;
|
|
|
|
|
|
// 2018-01-25 huibong 토토지원 과금 IP 확인용 임시 코드
|
|
char tempBuffer[40];
|
|
memset( tempBuffer, 0x00, sizeof( tempBuffer ) );
|
|
|
|
|
|
if (permitted) *permitted = 0;
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER START (%d) %s", getpid(), r->user);
|
|
#endif
|
|
|
|
|
|
/* get session key from user string */
|
|
rv = at_split(r->user, &ai);
|
|
if (rv == -1) {
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
} else if (rv == -2) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_user: user id format not match (%s)", r->user);
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
|
|
/* get cache info */
|
|
ac = dav_shared_ac_get_by_tranid(ai.szVolumeID);
|
|
if (!ac) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_user: cache not found.. is possible? (%s)", r->user);
|
|
/* Internal Error Condition, i know.
|
|
* if process this routine, old-type-anonymous auth type.
|
|
* to prevent smiliar type of error, return OK */
|
|
return OK;
|
|
//return HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
|
|
if ((permitted ? !ac->auth_uri[0] : !ac->bill_uri[0])) {
|
|
return OK;
|
|
}
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER MODE %c%c%c",
|
|
ac->mode[0], ac->mode[1], ac->mode[2]);
|
|
#endif
|
|
/* if old-auth or dav-auth */
|
|
if (ai.szSessionID[0] == '\0') {
|
|
if (IS_PERMIT_DAV_AUTH(ac)) {
|
|
return OK;
|
|
} else {
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
}
|
|
|
|
if (!strcmp(ai.szSessionID, ANONYMOUS_AUTH_MD5)) {
|
|
if (!IS_STRICTLY_ANONYMOUS(ac))
|
|
return OK;
|
|
}
|
|
|
|
/* if anonymous */
|
|
/* soft-line auth 내부 test 시 주석처리 */
|
|
if (!strcmp(ai.szSessionID, ANONYMOUS_MD5)) {
|
|
if (IS_PERMIT_ANONYMOUS(ac)) {
|
|
return OK;
|
|
} else {
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
}
|
|
|
|
// fill socket address structure */
|
|
rv = apr_sockaddr_info_get(&sa, AU_ADDR, APR_INET, AU_PORT, 0, r->pool);
|
|
//rv = apr_sockaddr_info_get(&sa, "1.2.3.4", APR_INET, ac->port, 0, r->pool);
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_user: failure to open to '%s:%d': %s",
|
|
AU_ADDR, AU_PORT, apr_strerror(rv, ebuf, sizeof ebuf));
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
/* make socket */
|
|
rv = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, r->pool);
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_user: create socket: %s",
|
|
apr_strerror(rv, ebuf, sizeof ebuf));
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
/* set timeout */
|
|
rv = apr_socket_timeout_set(sock, apr_time_from_sec(AU_TIMEOUT));
|
|
if (rv != APR_SUCCESS) {
|
|
apr_socket_close(sock);
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_user: set timeout: %s",
|
|
apr_strerror(rv, ebuf, sizeof ebuf));
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
|
|
|
|
|
|
/* connect */
|
|
rv = apr_socket_connect(sock, sa);
|
|
|
|
// 2018-01-25 huibong 토토지원 과금 IP 확인용 임시 코드
|
|
if( inet_ntop( AF_INET, &( sa->sa.sin.sin_addr ), tempBuffer, sizeof( tempBuffer ) ) == NULL )
|
|
{
|
|
sprintf( tempBuffer, "unknown" );
|
|
}
|
|
|
|
if (rv != APR_SUCCESS)
|
|
{
|
|
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_user: connect socket error: (%s/%s/%s) %s(%s):%d/%s: %s",
|
|
ac->tran_id, ac->seq, ai.szSessionID, AU_ADDR, tempBuffer, AU_PORT,
|
|
AU_URI, apr_strerror( rv, ebuf, sizeof ebuf ) );
|
|
|
|
return IS_STRICTLY_AUTH(ac) ? HTTP_UNAUTHORIZED : HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
/*
|
|
else
|
|
{
|
|
ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_user: connect socket ok: (%s/%s/%s) %s(%s):%d/%s",
|
|
ac->tran_id, ac->seq, ai.szSessionID, AU_ADDR, tempBuffer, AU_PORT,
|
|
AU_URI );
|
|
}
|
|
*/
|
|
|
|
|
|
/* make message */
|
|
#ifdef __OPENDAV_USER_AUTH_GET
|
|
pszMessage = apr_psprintf(r->pool, AUTH_USER_HEADER,
|
|
AU_URI, ai.szSessionID, AU_ADDR, AU_PORT, VERSION);
|
|
#else
|
|
//uri = ap_os_escape_path(r->pool, r->uri, 1);
|
|
//uri = r->uri;
|
|
//uri = ap_escape_logitem(r->pool, r->uri);
|
|
uri = apr_pcalloc(r->pool, strlen(r->uri) + 3);
|
|
dav_repos_restore_unsafe_chars(r->uri, uri);
|
|
*(uri + strlen(r->uri)) = '\0';
|
|
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER URI %s (%d)", uri, getpid());
|
|
#endif
|
|
//uri = dav_escape(r->pool, r->uri);
|
|
uri = dav_escape(r->pool, uri);
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER ESCAPE URI %s (%d)", uri, getpid());
|
|
#endif
|
|
|
|
|
|
|
|
// 2017-11-03 CHG huibong (revision 1426, ir #31497)
|
|
// - Apache 버전별 client ip 정보 추출
|
|
#if AP_SERVER_MAJORVERSION_NUMBER > 2 || AP_SERVER_MINORVERSION_NUMBER >= 3
|
|
pszClientIP = r->connection->client_ip;
|
|
#else // 2.2.x
|
|
pszClientIP = r->connection->remote_ip;
|
|
#endif // 2.3 over
|
|
|
|
|
|
#ifdef __USE_AUTH_SOFTLINE_ONLY__
|
|
|
|
// 2017-11-03 CHG huibong (revision 1426, ir #31497)
|
|
// - 토토디스크 측에서 BILL 정보에 request_time, end_time 항목 추가를 요청하여 기능 추가
|
|
// - 기존에는 AUTH, BILL 인자 항목이 동일하여 문제 없었지만, BILL 항목에 2개가 추가되어 코드 분리 처리함.
|
|
|
|
// pszBody = apr_psprintf( r->pool,
|
|
// ( permitted ?
|
|
// ( referer ? AUTH_USER_BODY_START AUTH_USER_BODY_REFERER : AUTH_USER_BODY_START )
|
|
// : ( referer ? BILL_DOWNLOAD AUTH_USER_BODY_END AUTH_USER_BODY_REFERER : BILL_DOWNLOAD AUTH_USER_BODY_END ) ),
|
|
// ai.szSessionID,
|
|
//#if AP_SERVER_MAJORVERSION_NUMBER > 2 || AP_SERVER_MINORVERSION_NUMBER >= 3
|
|
// uri, r->connection->client_ip, content, referer );
|
|
//#else // 2.2.x
|
|
// uri, r->connection->remote_ip, content, referer);
|
|
//#endif // 2.3 over
|
|
|
|
if( permitted ) // AUTH 관련 처리인 경우
|
|
{
|
|
pszBody = apr_psprintf( r->pool, ( referer ? AUTH_USER_BODY_START AUTH_USER_BODY_REFERER : AUTH_USER_BODY_START )
|
|
, ai.szSessionID
|
|
, uri, pszClientIP, content
|
|
, referer );
|
|
|
|
}
|
|
else // BILL 관련 처리인 경우
|
|
{
|
|
pszBody = apr_psprintf( r->pool, ( referer ? BILL_DOWNLOAD AUTH_USER_BODY_END AUTH_USER_BODY_REFERER : BILL_DOWNLOAD AUTH_USER_BODY_END )
|
|
, ai.szSessionID
|
|
, uri, pszClientIP, content, r->request_time, apr_time_now()
|
|
, referer );
|
|
}
|
|
|
|
|
|
#else // !__USE_AUTH_SOFTLINE_ONLY__
|
|
|
|
// pszBody = apr_psprintf(r->pool,
|
|
// (permitted ?
|
|
// (referer ? AUTH_USER_BODY_START AUTH_USER_BODY_REFERER :
|
|
// AUTH_USER_BODY_START)
|
|
// :
|
|
// (referer ? AUTH_USER_BODY_END AUTH_USER_BODY_REFERER :
|
|
// AUTH_USER_BODY_END)),
|
|
// ai.szSessionID,
|
|
//#if AP_SERVER_MAJORVERSION_NUMBER > 2 || AP_SERVER_MINORVERSION_NUMBER >= 3
|
|
// uri, r->connection->client_ip, content, referer);
|
|
//#else // 2.2.x
|
|
// uri, r->connection->remote_ip, content, referer);
|
|
//#endif // 2.3 over
|
|
|
|
if( permitted ) // AUTH 관련 처리인 경우
|
|
{
|
|
pszBody = apr_psprintf( r->pool, ( referer ? AUTH_USER_BODY_START AUTH_USER_BODY_REFERER : AUTH_USER_BODY_START )
|
|
, ai.szSessionID
|
|
, uri, pszClientIP, content
|
|
, referer );
|
|
}
|
|
else // BILL 관련 처리인 경우
|
|
{
|
|
pszBody = apr_psprintf( r->pool, ( referer ? AUTH_USER_BODY_END AUTH_USER_BODY_REFERER : AUTH_USER_BODY_END )
|
|
, ai.szSessionID
|
|
, uri, pszClientIP, content, r->request_time, apr_time_now()
|
|
, referer );
|
|
}
|
|
|
|
|
|
#endif // !__USE_AUTH_SOFTLINE_ONLY__
|
|
|
|
|
|
// 2015.07.16 dadamin
|
|
// 해당 인터페이스 공통(SDK)으로 적용되었으므로 모듈에서 동일하게 적용함
|
|
if (!permitted)
|
|
{
|
|
// 2013-03-26 : dadamin
|
|
// 고객사(토토로사) 요청으로 웹하드 등록제 통과를 위해서 다운로드 완료 시
|
|
// 추가된 header data를 추가로 전송될 수 있게 한다.
|
|
const char *ExtSessionID;
|
|
if ((ExtSessionID = apr_table_get(r->headers_in, "SB_ExtSession")))
|
|
{
|
|
pszBody = apr_psprintf(r->pool,"%s&%s", pszBody, ExtSessionID);
|
|
}
|
|
else
|
|
{
|
|
// 해당 header가 없을 경우 단순 log 처리
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "Extend the session does not exist.[%s]", uri);
|
|
}
|
|
}
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER MKBODY (%d)", getpid());
|
|
#endif
|
|
#ifdef __USE_AUTH_SOFTLINE_ONLY__
|
|
char szagent[20];
|
|
int ncontentlen = (int) strlen(pszBody);
|
|
|
|
// 소프트 라인에서 사용하고 있는 auth 경우 hearder가 고정크기이다.
|
|
// auth 경우 : 14+181, 과금 경우 : 14 + 184
|
|
// 고려 사항 : content length 경우 두자리, 네자리 숫자 염두
|
|
memset(szagent, 0, sizeof(szagent));
|
|
if( 9 < ncontentlen && ncontentlen < 100 ) // 두자리
|
|
{
|
|
strcpy(szagent, "WITH SOFTLINE ***");
|
|
}
|
|
else if ( 999 < ncontentlen ) // 네자리
|
|
{
|
|
strcpy(szagent, "WITH SOFTLINE *");
|
|
}
|
|
else // 나머지 (한자리,다섯자리 이상은 무시)
|
|
{
|
|
strcpy(szagent, "WITH SOFTLINE **");
|
|
}
|
|
|
|
pszMessage = apr_psprintf(r->pool, AUTH_USER_HEADER,
|
|
AU_URI, AU_ADDR, AU_PORT,
|
|
szagent, (int)strlen(pszBody), pszBody);
|
|
#else // __USE_AUTH_SOFTLINE_ONLY__
|
|
pszMessage = apr_psprintf(r->pool, AUTH_USER_HEADER,
|
|
AU_URI, AU_ADDR, AU_PORT,
|
|
VERSION, (int)strlen(pszBody), pszBody);
|
|
#endif // __SOFT_LINE_AUTH
|
|
#endif
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER E (%d) %s", getpid(), pszMessage);
|
|
#endif
|
|
|
|
/* send message */
|
|
bytes_send = strlen(pszMessage);
|
|
rv = apr_socket_send(sock, pszMessage, &bytes_send);
|
|
if (rv != APR_SUCCESS) {
|
|
apr_socket_close(sock);
|
|
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_user: failure to send message: (%s/%s/%s) %s:%d/%s: %s",
|
|
ac->tran_id, ac->seq, ai.szSessionID, AU_ADDR, AU_PORT,
|
|
AU_URI, apr_strerror(rv, ebuf, sizeof ebuf));
|
|
|
|
return IS_STRICTLY_AUTH(ac) ? HTTP_UNAUTHORIZED : HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
// 2011-03-20 소프트라인의 경우 인증은 응답대기, 과금은 응답대기하지 않도록 함.
|
|
#ifdef __USE_AUTH_SOFTLINE_ONLY__
|
|
if(permitted == NULL )
|
|
{
|
|
apr_socket_close(sock);
|
|
return OK;
|
|
}
|
|
|
|
#endif
|
|
|
|
/* receive message */
|
|
/* step 0: get header */
|
|
pszReceive = dav_auth_user_socket_recv(r->pool, sock, pszReceive);
|
|
if (pszReceive == NULL) {
|
|
apr_socket_close(sock);
|
|
return IS_STRICTLY_AUTH(ac) ? HTTP_UNAUTHORIZED : HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
/* step 1: parse content-length (or chunked) */
|
|
while ((is_chunked = dav_auth_user_body_type(pszReceive)) < 0) {
|
|
pszReceive = dav_auth_user_socket_recv(r->pool, sock, pszReceive);
|
|
if (pszReceive == NULL) {
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER ERR (%d) %s", getpid(), pszReceive);
|
|
#endif
|
|
apr_socket_close(sock);
|
|
return IS_STRICTLY_AUTH(ac) ? HTTP_UNAUTHORIZED : HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
}
|
|
|
|
/* step 2: get body */
|
|
/* step 3: check authrization */
|
|
|
|
|
|
while ((is_code = dav_auth_user_validate(r, pszReceive, is_chunked, permitted)) < 0) {
|
|
pszReceive = dav_auth_user_socket_recv(r->pool, sock, pszReceive);
|
|
if (pszReceive == NULL) {
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER ERR (%d) %s", getpid(), pszReceive);
|
|
#endif
|
|
apr_socket_close(sock);
|
|
return IS_STRICTLY_AUTH(ac) ? HTTP_UNAUTHORIZED : HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
}
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER D (%d) %s", getpid(), pszReceive);
|
|
#endif
|
|
|
|
apr_socket_close(sock);
|
|
|
|
return (is_code == 1 ? OK : HTTP_UNAUTHORIZED);
|
|
|
|
}
|
|
|
|
#ifdef __USE_AUTH_SOFTLINE_ONLY__
|
|
int dav_auth_upload_end_softline(request_rec *r, apr_off_t content, apr_off_t *permitted)
|
|
{
|
|
acct_info ai;
|
|
apr_status_t rv;
|
|
apr_socket_t *sock;
|
|
apr_sockaddr_t *sa;
|
|
char ebuf[128]; //, buf[120];
|
|
char *pszMessage
|
|
#ifndef __OPENDAV_USER_AUTH_GET
|
|
, *pszBody, *uri
|
|
#endif
|
|
;
|
|
apr_size_t bytes_send;
|
|
struct account_cache *ac;
|
|
const char *referer = apr_table_get(r->headers_in, "Referer");
|
|
|
|
if (permitted) *permitted = 0;
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER START (%d) %s", getpid(), r->user);
|
|
#endif
|
|
|
|
// 2016.05.27
|
|
// 위즈릴 제휴 컨텐츠 경우 FTP(SolDrive 마운트)를 통해서 업로드됨
|
|
// 이 경우 해당 과금 서버로 다수 요청될 수 있으므로 해당 과금 서버 안정성을 위해서 예외 처리함.
|
|
// 참고 : 해당 컨텐츠 업로드 완료 후 연동되는 인터페이스(ASP 구성된 서버)에서 과금서버(트랜스코딩요청)호출됨
|
|
const char * userAgent = NULL;
|
|
userAgent = apr_table_get( r->headers_in, "User-Agent");
|
|
if(userAgent != NULL && strncmp(userAgent, "NetCache", 8) == 0 )
|
|
{
|
|
if(r && r->server)
|
|
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, "SKIP : Soldrive upload.[%s]", r->uri);
|
|
return OK;
|
|
}
|
|
|
|
|
|
/* get session key from user string */
|
|
rv = at_split(r->user, &ai);
|
|
if (rv == -1) {
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
} else if (rv == -2) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_upload_end_softline: user id format not match (%s)", r->user);
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
|
|
/* get cache info */
|
|
ac = dav_shared_ac_get_by_tranid(ai.szVolumeID);
|
|
if (!ac) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"dav_auth_upload_end_softline: cache not found.. is possible? (%s)", r->user);
|
|
/* Internal Error Condition, i know.
|
|
* if process this routine, old-type-anonymous auth type.
|
|
* to prevent smiliar type of error, return OK */
|
|
return OK;
|
|
//return HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
|
|
if ((permitted ? !ac->auth_uri[0] : !ac->bill_uri[0])) {
|
|
return OK;
|
|
}
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER MODE %c%c%c",
|
|
ac->mode[0], ac->mode[1], ac->mode[2]);
|
|
#endif
|
|
/* if old-auth or dav-auth */
|
|
if (ai.szSessionID[0] == '\0') {
|
|
// PUT not used;
|
|
}
|
|
|
|
if (!strcmp(ai.szSessionID, ANONYMOUS_AUTH_MD5)) {
|
|
if (!IS_STRICTLY_ANONYMOUS(ac))
|
|
return OK;
|
|
}
|
|
|
|
/* if anonymous */
|
|
/* soft-line auth 내부 test 시 주석처리 */
|
|
if (!strcmp(ai.szSessionID, ANONYMOUS_MD5)) {
|
|
if (IS_PERMIT_ANONYMOUS(ac)) {
|
|
return OK;
|
|
} else {
|
|
return HTTP_UNAUTHORIZED;
|
|
}
|
|
}
|
|
|
|
// fill socket address structure */
|
|
rv = apr_sockaddr_info_get(&sa, AU_ADDR, APR_INET, AU_PORT, 0, r->pool);
|
|
//rv = apr_sockaddr_info_get(&sa, "1.2.3.4", APR_INET, ac->port, 0, r->pool);
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_upload_end_softline: failure to open to '%s:%d': %s",
|
|
AU_ADDR, AU_PORT, apr_strerror(rv, ebuf, sizeof ebuf));
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
/* make socket */
|
|
rv = apr_socket_create(&sock, sa->family, SOCK_STREAM, APR_PROTO_TCP, r->pool);
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_upload_end_softline: create socket: %s",
|
|
apr_strerror(rv, ebuf, sizeof ebuf));
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
/* set timeout */
|
|
rv = apr_socket_timeout_set(sock, apr_time_from_sec(BILL_UPLOAD_END_SEND_TIMEOUT));
|
|
if (rv != APR_SUCCESS) {
|
|
apr_socket_close(sock);
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_upload_end_softline: set timeout: %s",
|
|
apr_strerror(rv, ebuf, sizeof ebuf));
|
|
return HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
/* connect */
|
|
rv = apr_socket_connect(sock, sa);
|
|
if (rv != APR_SUCCESS) {
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_upload_end_softline: failure to connect socket: (%s/%s/%s - %" APR_OFF_T_FMT ") %s:%d/%s: %s",
|
|
ac->tran_id, ac->seq, r->uri, content, AU_ADDR, AU_PORT,
|
|
AU_URI, apr_strerror(rv, ebuf, sizeof ebuf));
|
|
|
|
return IS_STRICTLY_AUTH(ac) ? HTTP_UNAUTHORIZED : HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
/* make message */
|
|
#ifdef __OPENDAV_USER_AUTH_GET
|
|
pszMessage = apr_psprintf(r->pool, AUTH_USER_HEADER,
|
|
AU_URI, ai.szSessionID, AU_ADDR, AU_PORT, VERSION);
|
|
#else
|
|
//uri = ap_os_escape_path(r->pool, r->uri, 1);
|
|
//uri = r->uri;
|
|
//uri = ap_escape_logitem(r->pool, r->uri);
|
|
uri = apr_pcalloc(r->pool, strlen(r->uri) + 3);
|
|
dav_repos_restore_unsafe_chars(r->uri, uri);
|
|
*(uri + strlen(r->uri)) = '\0';
|
|
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER URI %s (%d)", uri, getpid());
|
|
#endif
|
|
|
|
//uri = dav_escape(r->pool, uri); 차진호 과장님 요청으로 URI인코딩하지 않음. 2011년 03월 21일
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER ESCAPE URI %s (%d)", uri, getpid());
|
|
#endif
|
|
|
|
#define FIXED_SESSION_ID "201S103wolt1920220h893ds10da3da3"
|
|
|
|
pszBody = apr_psprintf(r->pool,
|
|
(permitted ?
|
|
(referer ? AUTH_USER_BODY_START AUTH_USER_BODY_REFERER :
|
|
AUTH_USER_BODY_START)
|
|
:
|
|
(referer ? BILL_UPLOAD BILL_UPLOAD_END AUTH_USER_BODY_REFERER :
|
|
BILL_UPLOAD BILL_UPLOAD_END)),
|
|
FIXED_SESSION_ID,
|
|
#if AP_SERVER_MAJORVERSION_NUMBER > 2 || AP_SERVER_MINORVERSION_NUMBER >= 3
|
|
uri, r->connection->client_ip, content, referer);
|
|
#else // 2.2.x
|
|
uri, r->connection->remote_ip, content, referer);
|
|
#endif // 2.3 over
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER MKBODY (%d)", getpid());
|
|
#endif
|
|
|
|
if(!permitted)
|
|
{
|
|
// 2013-06-26 : dadamin
|
|
// 고객사(토토로사) 요청으로 솔루션 연동을 위해서 업로드 완료 후
|
|
// 추가된 header data를 추가로 전송될 수 있게 한다.
|
|
const char *ExtSessionID;
|
|
if ((ExtSessionID = apr_table_get(r->headers_in, "SB_ExtSession")))
|
|
{
|
|
pszBody = apr_psprintf(r->pool,"%s&%s", pszBody, ExtSessionID);
|
|
}
|
|
else
|
|
{
|
|
// 해당 header가 없을 경우 단순 log 처리
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "PUT Extend the session does not exist.[%s]", uri);
|
|
}
|
|
}
|
|
|
|
char szagent[20];
|
|
int ncontentlen = (int) strlen(pszBody);
|
|
|
|
// 소프트 라인에서 사용하고 있는 auth 경우 hearder가 고정크기이다.
|
|
// auth 경우 : 14+181, 과금 경우 : 14 + 184
|
|
// 고려 사항 : content length 경우 두자리, 네자리 숫자 염두
|
|
memset(szagent, 0, sizeof(szagent));
|
|
if( 9 < ncontentlen && ncontentlen < 100 ) // 두자리
|
|
{
|
|
strcpy(szagent, "WITH SOFTLINE ***");
|
|
}
|
|
else if ( 999 < ncontentlen ) // 네자리
|
|
{
|
|
strcpy(szagent, "WITH SOFTLINE *");
|
|
}
|
|
else // 나머지 (한자리,다섯자리 이상은 무시)
|
|
{
|
|
strcpy(szagent, "WITH SOFTLINE **");
|
|
}
|
|
|
|
pszMessage = apr_psprintf(r->pool, AUTH_USER_HEADER,
|
|
AU_URI, AU_ADDR, AU_PORT,
|
|
szagent, (int)strlen(pszBody), pszBody);
|
|
|
|
#endif
|
|
|
|
#ifdef __OPENDAV_DEBUG_USER_AUTH__
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "P_USER E (%d) %s", getpid(), pszMessage);
|
|
#endif
|
|
|
|
/* send message */
|
|
bytes_send = strlen(pszMessage);
|
|
rv = apr_socket_send(sock, pszMessage, &bytes_send);
|
|
if (rv != APR_SUCCESS) {
|
|
apr_socket_close(sock);
|
|
|
|
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
|
|
"OPENDAV: dav_auth_upload_end_softline: failure to send message: (%s/%s/%s - %" APR_OFF_T_FMT ") %s:%d/%s: %s",
|
|
ac->tran_id, ac->seq, uri, content, AU_ADDR, AU_PORT,
|
|
AU_URI, apr_strerror(rv, ebuf, sizeof ebuf));
|
|
|
|
return IS_STRICTLY_AUTH(ac) ? HTTP_UNAUTHORIZED : HTTP_INTERNAL_SERVER_ERROR;
|
|
}
|
|
|
|
// 2011-03-20 huibong
|
|
// Upload 정보를 보내고 소프트라인 서버에 대한 응답대기를 하지 않는다. ( 차진호 과장 확인사항 )
|
|
apr_socket_close(sock);
|
|
|
|
return OK;
|
|
}
|
|
|
|
void dav_auth_upload_end(dav_resource_private *info)
|
|
{
|
|
#ifdef __USE_AUTH_SOFTLINE_ONLY_UPLOAD_END_SEND_
|
|
if (!info->db_r || !info->db_r->r)
|
|
return;
|
|
|
|
dav_auth_upload_end_softline(info->db_r->r, info->db_r->m_get_content_length, NULL);
|
|
#endif // __USE_AUTH_SOFTLINE_ONLY_UPLOAD_END_SEND_
|
|
return;
|
|
}
|
|
#endif // __USE_AUTH_SOFTLINE_ONLY__
|