/**************************************************************************** mod_dav_pgsql (DASL) for apache 2.X CopyRight(C) 2005 SolutionBox Inc. All Rights reserved. Author : sean kim (sean@solutionbox.co.kr) $Id: util.c,v 1.5 2007/03/19 08:43:12 elenoa Exp $ Redistribution and use in source and binary forms, with or with out modification, are not permitted in outside of SolutionBox Inc. ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include /* for ap_construct_url */ #include #include #include #include #include #include #include #include #include #include "dav_repos.h" #include "dbms.h" #include "util.h" /* Note: the "dav_repos" prefix is mandatory */ extern module AP_MODULE_DECLARE_DATA dav_repos_module; /*****************************/ /* common functions */ // FreeBSD 6.2 설치된 iconv 경우 iconv에 srcbuf를 const char* 로 받음 #ifdef __FreeBSD__ static char *iconv_string(apr_pool_t *p, iconv_t cd, const char *srcbuf, size_t srclen) #else // !__FreeBSD__ static char *iconv_string(apr_pool_t *p, iconv_t cd, char *srcbuf, size_t srclen) #endif // __FreeBSD__ { char *outbuf, *marker; size_t outlen; if (srclen == 0) { #ifdef __FreeBSD__ return (char *)srcbuf; #else // !__FreeBSD__ return srcbuf; #endif // __FreeBSD__ } /* Allocate space for conversion. Note max bloat factor is 4 of UCS-4 */ marker = outbuf = (char *)apr_palloc(p, outlen = srclen * 4 + 1); if (outbuf == NULL) { return NULL; } /* Convert every character within input string. */ while (srclen > 0) { #ifdef __FreeBSD__ if (iconv(cd, (const char **)&srcbuf, &srclen, &outbuf, &outlen) == (size_t)(-1)) #else // !__FreeBSD__ if (iconv(cd, &srcbuf, &srclen, &outbuf, &outlen) == (size_t)(-1)) #endif // __FreeBSD__ { return NULL; } } *outbuf = '\0'; return marker; } // NEW 2019-09-18 huibong 인코딩 처리 관련 신규 추가 (#32584) // - URL 인코딩에 대한 판단 오류 상황을 보완하기 위해 인터넷에 유통 중인 소스 중 신뢰성 있는 소스의 기능을 추가 // - 본 소스는 전달받은 문자열이 UTF-8 인코딩인지를 판단하는 함수로서 // - android base 소스에 등록된 함수임 // - 참고자료 // -- https://android.googlesource.com/platform/frameworks/base/+/master/media/jni/android_media_MediaScanner.cpp static bool isValidUtf8( const char * bytes ) { while( *bytes != '\0' ) { unsigned char utf8 = *( bytes++ ); //ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "isValidUtf8: [%c][%02X][%02X]", utf8, utf8, utf8>>4); // Switch on the high four bits. switch( utf8 >> 4 ) { case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07: // Bit pattern 0xxx. No need for any extra bytes. break; case 0x08: case 0x09: case 0x0a: case 0x0b: case 0x0f: /* * Bit pattern 10xx or 1111, which are illegal start bytes. * Note: 1111 is valid for normal UTF-8, but not the * modified UTF-8 used here. */ return false; case 0x0e: // Bit pattern 1110, so there are two additional bytes. utf8 = *( bytes++ ); if( ( utf8 & 0xc0 ) != 0x80 ) { return false; } // Fall through to take care of the final byte. //FALLTHROUGH_INTENDED; case 0x0c: case 0x0d: // Bit pattern 110x, so there is one additional byte. utf8 = *( bytes++ ); //ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "isValidUtf8: [%c][%02X][%02X]", utf8, utf8, utf8 & 0xc0 ); if( ( utf8 & 0xc0 ) != 0x80 ) { return false; } // ADD 2019-09-18 huibong 연관일감 #21096 관련 회피 기능 추가 ((#32584) // - "책" 문자열이 utf-8 로 인식되는 거를 막기 위해 회피하도록 조건 추가 if( utf8 == 0xa5 ) { return false; } break; } } return true; } // CHG 2019-09-18 huibong URL의 정확한 인코딩 탐지 실패 관련 기능 보완 (#32584) // - #32584 에서 UTF-8 기반 url 을 UHC 로 인식하는 문제 발생 // - UTF-8, UHC 혼합사용으로 인해 정확한 탐지를 실패할 가능성이 존재하지만..... // - 이를 조금이라도 보완하기 위해 인코딩 check 로직을 보완함. static int is_valid_uhc( char * buf ) { // CHG 2019-09-18 huibong UTF-8 enconding 인지 check 기능 추가 (#32584) // - 우선 기본으로 UTF-8 인 요청을 거른다. // - 인코딩 특성상 UHC 인데.. UTF-8 로 인식될 가능성이 있다. // - 이런 경우에는 isValidUtf8() 함수에 해당 요청에 대한 예외를 추가하는 방법 밖에 없다. if( isValidUtf8( buf ) == true ) { //ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "is_valid_uhc: isValidUtf8() return UTF-8 [%s]", buf ); return 0; } // 일단 UTF-8 인코딩이 아니라고 판단된 경우.... // - 대부분 UHC 이겠지만.... // - UTF-8 인데.. 예외 처리 등으로 UHC 로 잘못 판정될 가능성 존재하므로..... // - iconv 를 이용하여 다시 UHC 인지 다시 확인한다. char outBuf[4096] = { 0 }; iconv_t cd = iconv_open( "UTF-8", "UHC" ); if( cd == (iconv_t)( -1 ) ) { ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "is_valid_uhc: iconv open failed [%s]", buf ); return 0; } size_t readBytes = strlen( buf ); size_t writeBytes = sizeof( outBuf ); char * in = buf; char * out = outBuf; if( iconv( cd, (const char **)& in, &readBytes, &out, &writeBytes ) == (size_t)-1 ) { int errorNum = errno; iconv_close( cd ); // UHC -> UTF-8 로 변환 실패시... // - 변환 성공시 UHC 이지만.. 변환 실패시에는 UTF-8 로 판정한다. ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "is_valid_uhc: iconv UHC->UTF-8 error. reuturn UTF-8 [%d][%s]", errorNum, buf ); return 0; } iconv_close( cd ); // 최종 UHC 로 판정한다. //ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "is_valid_uhc: return UHC [%s]", buf ); return 1; } // UTF-8 -> Database Character Set char* transformDBCharacter(request_rec *r, char* srcbuf, char *prefixmsg ) { char *ret = NULL; char *srccharset = NULL, *destcharset = NULL; dav_repos_server_conf *conf = NULL; conf = dav_repos_get_server_conf(r->server); iconv_t cd; if( conf == NULL ) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s: dav_repos_get_server_conf NULL. return srcbuf", prefixmsg); return srcbuf; } if( conf->db_charset == NULL ) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s: config DavProviderDBCharset set NULL. return srcbuf", prefixmsg); return srcbuf; } destcharset = (char *) conf->db_charset; // Database Character UTF-8 지원 시 해당 로직은 수행하지 않음 if (strcmp( destcharset, "UTF-8") == 0) { return srcbuf; } // check UHC Character if ( is_valid_uhc(srcbuf) == 1) { ap_log_error( APLOG_MARK, APLOG_ERR, 0, NULL, "transformDBCharacter: url encoding is UHC [%s][%s]", prefixmsg, srcbuf); srccharset = "UHC"; } else { //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "transformDBCharacter: url encoding is UTF-8 [%s][%s]", prefixmsg, srcbuf); srccharset = "UTF-8"; } // unknown Character set and return srcbuf if( srccharset == NULL ) { return srcbuf; } // compare character set if( strcmp(srccharset, destcharset) == 0 ) { //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s: same Character [%s]", prefixmsg, srcbuf); return srcbuf; } // transform src character set -> DB character set cd = iconv_open(destcharset, srccharset); if( cd == (iconv_t)(-1)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s: iconv open failed [%s]", prefixmsg, srcbuf); ret = apr_pstrdup(r->pool, srcbuf); } else { ret = iconv_string(r->pool, cd, srcbuf, strlen(srcbuf)); if (ret == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s: iconv error [%s]",prefixmsg, srcbuf); ret = apr_pstrdup(r->pool, srcbuf); } iconv_close(cd); } return ret; } // Database Character Set -> UTF-8 char* transformUTF8(request_rec *r, char* srcbuf, char *prefixmsg ) { char *ret = NULL; char *srccharset = NULL, *destcharset = NULL; dav_repos_server_conf *conf = NULL; conf = dav_repos_get_server_conf(r->server); iconv_t cd; destcharset = "UTF-8"; if( conf == NULL ) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s: dav_repos_get_server_conf NULL. return srcbuf", prefixmsg); return srcbuf; } if( conf->db_charset == NULL ) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s: config DavProviderDBCharset set NULL. return srcbuf", prefixmsg); return srcbuf; } // check UHC Character if (is_valid_uhc(srcbuf) == 1) { srccharset = "UHC"; } else { srccharset = "UTF-8"; } // compare character set if( strcmp(srccharset, destcharset) == 0 ) { return srcbuf; } // transform DB character set -> UTF-8 cd = iconv_open(destcharset, srccharset); if( cd == (iconv_t)(-1)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s: iconv open failed [%s]", prefixmsg, srcbuf); ret = apr_pstrdup(r->pool, srcbuf); } else { ret = iconv_string(r->pool, cd, srcbuf, strlen(srcbuf)); if (ret == NULL) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL, "%s: iconv error[%s]", prefixmsg, srcbuf); ret = apr_pstrdup(r->pool, srcbuf); } iconv_close(cd); } return ret; } int dav_repos_remove_base_uri(const char *base_uri, const char *req_uri, char *result) { int nCount = 0; int req_uri_length = 0; if((base_uri == NULL) || (req_uri == NULL) || (result == NULL)) { return -1; } req_uri_length = strlen(req_uri); if(req_uri_length == 1) { if((*req_uri == '/') || (*req_uri == '\0') || (*req_uri == ' ')) { result[0] = '/'; result[1] = '\0'; } else { return -2; } return 1; } else if(req_uri_length == 0) { return -3; } while((*req_uri != '\0') && (*base_uri != '\0')) { if(*base_uri == *req_uri) { base_uri++; req_uri++; } else { break; } } while(*req_uri != '\0') { result[nCount++] = *req_uri++; } result[nCount] = '\0'; return 1; } int remove_user_root_dir_from_fake_uri(const char *pcszFakeURI, char *pURI) { int nCount = 0; int sCount = 0; char sztmpBuffer[MaxSizeOfPathLength]; if(pcszFakeURI == NULL) { return -1; } if(strlen(pcszFakeURI) > MaxSizeOfPathLength) { return -2; } while(*pcszFakeURI != '\0') { if(*pcszFakeURI == '/') { sCount++; if(sCount == 2) { nCount = 0; memset(sztmpBuffer, 0, MaxSizeOfPathLength); sztmpBuffer[nCount++] = *pcszFakeURI++; } } sztmpBuffer[nCount++] = *pcszFakeURI++; } sztmpBuffer[nCount] = '\0'; snprintf(pURI, MaxSizeOfPathLength, "%s", sztmpBuffer); return 1; } int get_filename_in_path(const char *pcszPath, char *pszPathName, char *pszFileName) { int nCount = 0; char sztmpBuffer[MaxSizeOfPathLength]; if((pcszPath == NULL) || (pszFileName == NULL) || (pszPathName == NULL)) { return -1; } if(strlen(pcszPath) > MaxSizeOfPathLength) { return -2; } memset(sztmpBuffer, 0, MaxSizeOfPathLength); while(*pcszPath != '\0') { if(*pcszPath == '/') { sztmpBuffer[nCount++] = *pcszPath++; if(*pcszPath == '\0') { break; } sztmpBuffer[nCount] = '\0'; //DBG1("get_filename_in_path::sztmpBuffer = %s", sztmpBuffer); strncat(pszPathName, sztmpBuffer, MaxSizeOfPathLength - strlen(pszPathName)); nCount = 0; memset(sztmpBuffer, 0, MaxSizeOfPathLength); } sztmpBuffer[nCount++] = *pcszPath++; } sztmpBuffer[nCount] = '\0'; snprintf(pszFileName, MaxSizeOfPathLength, "%s", sztmpBuffer); return 1; } // CHG 2010-08-10 huibong // Hash 정보 생성 처리시 생성 결과를 static 변수에 저장하고 // 해당 변수를 반환처리 하는 경우 .. // 동시간 접근시 Lock 을 사용하지 않게 되면 문제가 발생하게 됨. ( File Name에 대한 Hash 정보가 동일하게 생성) // 하지만 Lock 을 처리속도에 영향을 미칠수 있으므로 // 결과 값을 저장할 출력변수를 매개변수로 전달받도록 수정처리 한다. //char *get_hashed_filepath(const char *plain_filepath) bool get_hashed_filepath( const char *plain_filepath, char * result, int result_length) { // 매개변수에 대한 검증 처리 if( plain_filepath == NULL || result == NULL || result_length < (APR_MD5_DIGESTSIZE * 2 + 1)) return false; else { // 출력값을 저장할 변수가 적합한 경우. int i; unsigned char digest[APR_MD5_DIGESTSIZE]; apr_md5(digest, (const unsigned char *) plain_filepath, strlen(plain_filepath)); // 화면에 표시 가능하도록 Hex 처리. for (i = 0; i < APR_MD5_DIGESTSIZE; i++) apr_snprintf((char *) &result[i + i], 3, "%02x", digest[i]); result[APR_MD5_DIGESTSIZE * 2] = '\0'; return true; } } /* split user_login_id@partner_login_id into */ /* user_login_id, partner_login_id */ /* 2007. 07. 30: Elenoa Lazyfake * r->user format changed: for classified traffic manage * (in Makefile, __CLASSIFIED_TRAFFIC_MANAGE__) * from: tranid@userid@sessionkey * to: tranid.classid@userid@sessionkey */ int at_split(const char *pszAcctInfo, acct_info *pAcctInfo) { int fFound = 0; int chCount = 0; char sztmpBuffer[MaxSizeOfAcctSession + 1]; if((pszAcctInfo == NULL) || (pAcctInfo == NULL)) { return -1; } /* 0nd step : clear acct_info buffer */ memset((char *)pAcctInfo, 0, sizeof(acct_info)); /* 1st step : parse user login id */ fFound = 0; chCount = 0; memset(sztmpBuffer, 0, MaxSizeOfAcctVolume); while(*pszAcctInfo != '\0') { if(*pszAcctInfo == '@') { sztmpBuffer[chCount] = '\0'; snprintf(pAcctInfo->szVolumeID, MaxSizeOfAcctVolume, "%s", sztmpBuffer); DBG1("at_split::sztmpBuffer #1(end) = %s", sztmpBuffer); fFound = -1; break; } #ifdef __CLASSIFIED_TRAFFIC_MANAGE__ if(*pszAcctInfo == '.') { sztmpBuffer[chCount] = '\0'; snprintf(pAcctInfo->szVolumeID, MaxSizeOfAcctVolume, "%s", sztmpBuffer); DBG1("at_split::sztmpBuffer #1(cont') = %s", sztmpBuffer); fFound = 1; break; } #endif sztmpBuffer[chCount++] = *pszAcctInfo++; } #ifdef __CLASSIFIED_TRAFFIC_MANAGE__ if (fFound == -1) { sprintf(pAcctInfo->szTCClassID, "0"); goto second_step; } #endif if (fFound == 0) { #ifdef __CLASSIFIED_TRAFFIC_MANAGE__ pAcctInfo->szTCClassID[0] = '\0'; #endif return -2; } #ifdef __CLASSIFIED_TRAFFIC_MANAGE__ fFound = 0; chCount = 0; pszAcctInfo++; memset(sztmpBuffer, 0, MaxSizeOfAcctVolume); while(*pszAcctInfo != '\0') { if(*pszAcctInfo == '@') { sztmpBuffer[chCount] = '\0'; snprintf(pAcctInfo->szTCClassID, MaxSizeOfAcctVolume, "%s", sztmpBuffer); DBG1("at_split::sztmpBuffer #1(cid) = %s", sztmpBuffer); fFound = 1; break; } sztmpBuffer[chCount++] = *pszAcctInfo++; } if(fFound != 1) { return -3; } second_step: #endif /* 2nd step : parse partner login id */ fFound = 0; chCount = 0; pszAcctInfo++; memset(sztmpBuffer, 0, MaxSizeOfAcctUserID); while(*pszAcctInfo != '\0') { if(*pszAcctInfo == '@') { sztmpBuffer[chCount] = '\0'; snprintf(pAcctInfo->szUserID, MaxSizeOfAcctUserID, "%s", sztmpBuffer); DBG1("at_split::sztmpBuffer #2 = %s", sztmpBuffer); fFound = 1; break; } sztmpBuffer[chCount++] = *pszAcctInfo++; } if(fFound != 1) { sztmpBuffer[chCount] = '\0'; snprintf(pAcctInfo->szUserID, MaxSizeOfAcctUserID, "%s", sztmpBuffer); DBG1("at_split::sztmpBuffer #2 = %s, #3 none", sztmpBuffer); pAcctInfo->szSessionID[0] = '\0'; } else { /* 3rd step : parse session id */ chCount = 0; memset(sztmpBuffer, 0, MaxSizeOfAcctSession); pszAcctInfo++; while(*pszAcctInfo != '\0') { sztmpBuffer[chCount++] = *pszAcctInfo++; } sztmpBuffer[chCount] = '\0'; snprintf(pAcctInfo->szSessionID, MaxSizeOfAcctSession, "%s", sztmpBuffer); DBG1("at_split::sztmpBuffer #3 = %s", sztmpBuffer); } return 1; } int check_string(char *to, const char *from, size_t length) { int nCount = 0; char tmpBuff[length]; if((to == NULL) || (from == NULL)) { return -1; } while((*from != '\0') && (length > 0)) { if(*from != '\'') { tmpBuff[nCount++] = *from; } from++; length--; } tmpBuff[nCount] = '\0'; snprintf(to, nCount + 1, "%s", tmpBuff); return 1; } /*************************/ /* configuration support */ dav_repos_server_conf *dav_repos_get_server_conf( server_rec *s ) { if( s == NULL ) return NULL; else return ap_get_module_config(s->module_config, &dav_repos_module); } inline void dav_spin_wait(int vsleep) { struct timeval tv; tv.tv_sec = 0; tv.tv_usec = vsleep; select (0, NULL, NULL, NULL, &tv); } ap_dbd_t *dav_repos_get_db(request_rec *r) { ap_dbd_t *db; /* loop until get acquire db session */ if( (db = ap_dbd_open(r->server->process->pool, r->server)) != NULL ) { return db; } /* can reach here? */ ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "OPENDAV:dav_repos_get_db database connection pool error."); return NULL; } void dav_repos_release_db(request_rec *r, ap_dbd_t *db, int o_rv) { int retval; { ap_dbd_close(r->server, db); retval = OK; } if (retval == !OK) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, r->server, "OPENDAV: database not properly released"); } } int dav_repos_begin_trans(const char *func, request_rec *r, ap_dbd_t *db, apr_dbd_transaction_t **trans) { int rv; rv = apr_dbd_transaction_start(db->driver, r->pool, db->handle, trans); if (rv) { char errbuf[1024]; sprintf(errbuf, "%s: begin transaction", func); db_error_message(db, errbuf, rv); dav_repos_release_db(r, db, rv); //apr_thread_rwlock_unlock(db_lock); return -20; } return 0; } int dav_repos_end_trans(const char *func, request_rec *r, ap_dbd_t *db, apr_dbd_transaction_t *trans) { int rv; rv = apr_dbd_transaction_end(db->driver, r->pool, trans); if (rv) { char errbuf[1024]; sprintf(errbuf, "%s: end transaction", func); db_error_message(db, errbuf, rv); dav_repos_release_db(r, db, rv); //apr_thread_rwlock_unlock(db_lock); return -21; } return 0; } /* Note: picked up from ap_gm_timestr_822() */ /* NOTE: buf must be at least DAV_TIMEBUF_SIZE chars in size */ void dav_repos_format_time(int style, apr_time_t sec, char *buf) { apr_time_exp_t tms; DBG1("dav_repos_format_time:sec = %" APR_TIME_T_FMT "", sec); (void) apr_time_exp_gmt(&tms, sec); TRACE(); if (style == DAV_STYLE_ISO8601) { /* ### should we use "-00:00" instead of "Z" ?? */ /* 20 chars plus null term */ sprintf(buf, "%.4d-%.2d-%.2dT%.2d:%.2d:%.2dZ", tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday, tms.tm_hour, tms.tm_min, tms.tm_sec); } else { /* RFC 822 date format; as strftime '%a, %d %b %Y %T GMT' */ /* 29 chars plus null term */ sprintf(buf, "%s, %.2d %s %d %.2d:%.2d:%.2d GMT", apr_day_snames[tms.tm_wday], tms.tm_mday, apr_month_snames[tms.tm_mon], tms.tm_year + 1900, tms.tm_hour, tms.tm_min, tms.tm_sec); } DBG1("dav_repos_format_time:buf = %s", buf); } const char *dav_repos_build_ns_name_key(const char *ns, const char *name, apr_pool_t * pool) { TRACE(); /* Woops */ if (ns == NULL || name == NULL || pool == NULL) return NULL; if (strlen(ns)==0) ns=" "; /* No namespace */ return apr_psprintf(pool, "%s\t%s", ns, name); } void dav_repos_get_ns_name_key(const char *key, dav_prop_name * pname, apr_pool_t * pool) { char *str; pname->ns = pname->name = NULL; /* Woops */ if (key == NULL || pool == NULL) return; str = apr_pstrdup(pool, key); pname->ns = strtok(str, "\t"); pname->name = strtok(NULL, "\t"); } /* Make XML response */ dav_response *dav_repos_mkresponse(dav_repos_resource * db_r) { int i; char *s = NULL; const char *ns; apr_text_header hdr = { 0 }; apr_text_header hdr_ns = { 0 }; dav_response *res = apr_pcalloc(db_r->p, sizeof(*res)); dav_repos_property *dead_prop; char *ns_use = apr_pcalloc(db_r->p, DAV_REPOS_MAX_NAMESPACE); /* Maximul namespaces */ /* Resopnse Example / 2001-10-22T02:46:33Z Mon, 22 Oct 2001 02:46:33 GMT "59272-1000-7e1c7440" httpd/unix-directory HTTP/1.1 200 OK */ /* Make fake data for test */ res->href = db_r->m_uri; res->status = 200; TRACE(); DBG0("dav_repos_mkresponse:"); /* Generate namespace first */ /* Dead properties */ for (dead_prop = db_r->pr; dead_prop; dead_prop = dead_prop->next) { ns_use[(int) dead_prop->m_ns_id] = 1; } /* Add namespace for dead properties */ for (i = 0; i < DAV_REPOS_MAX_NAMESPACE; i++) { if (ns_use[i] == 1) { ns = dbms_get_ns(db_r, i); if (ns == NULL || strlen(ns) == 0) { ns_use[i] = -1; /* nullns */ } else { s = apr_psprintf(db_r->p, " xmlns:%s%d=\"%s\"", "ns", i, ns); apr_text_append(db_r->p, &hdr_ns, s); } } } /* Make XML here */ apr_text_append(db_r->p, &hdr, "" DEBUG_CR "" DEBUG_CR); /* Start prop */ /* Dead properties */ for (dead_prop = db_r->pr; dead_prop; dead_prop = dead_prop->next) { /* Null ns need xmlns="" */ if (ns_use[(int) dead_prop->m_ns_id] == -1) { s = apr_psprintf(db_r->p, "<%s xmlns=\"\">%s" DEBUG_CR, dead_prop->m_propname, dead_prop->m_propvalue, dead_prop->m_propname); } else { s = apr_psprintf(db_r->p, "%s" DEBUG_CR, dead_prop->m_ns_id, dead_prop->m_propname, dead_prop->m_propvalue, dead_prop->m_ns_id, dead_prop->m_propname); } apr_text_append(db_r->p, &hdr, s); ns_use[(int) dead_prop->m_ns_id] = 1; } /* Live properties */ if (db_r->lpr_hash) /* build it before mkresponse */ { long klen; const char *stmp; const char *key, *val; apr_hash_index_t *hindex; /* Read live props from hash */ for (hindex = apr_hash_first(db_r->p, db_r->lpr_hash); hindex; hindex = apr_hash_next(hindex)) { apr_hash_this(hindex, (void *) &key, &klen, (void *) &val); stmp = apr_psprintf(db_r->p, "%s" DEBUG_CR, key, val, key); DBG1("dav_repos_mkresponse: %s", stmp); apr_text_append(db_r->p, &hdr, stmp); } } /* Lock discovery print, if we have */ /* FIXME : Do we really need lock info for search */ #if 0 apr_text_append(db_r->p, &hdr, "" DEBUG_CR); if (db_r->lockdiscovery) apr_text_append(db_r->p, &hdr, db_r->lockdiscovery); apr_text_append(db_r->p, &hdr, "" DEBUG_CR); /* Supported lock */ if (db_r->supportedlock) apr_text_append(db_r->p, &hdr, db_r->supportedlock); #endif /* Closing */ apr_text_append(db_r->p, &hdr, "" DEBUG_CR "HTTP/1.1 200 OK" DEBUG_CR "" DEBUG_CR); /* ** name space set up ** Better way?? */ s = apr_psprintf(db_r->p, " xmlns:%s%d=\"%s\"", "lp", 0, "DAV:"); apr_text_append(db_r->p, &hdr_ns, s); s = apr_psprintf(db_r->p, " xmlns:%s%d=\"%s\"", "lp", 1, "DAV:"); apr_text_append(db_r->p, &hdr_ns, s); res->propresult.propstats = hdr.first; res->propresult.xmlns = hdr_ns.first; return res; } /* Build dead property hash * Build the hash before makeresponse */ void dav_repos_build_pr_hash(dav_repos_resource * db_r) { dav_repos_property *dead_prop; TRACE(); /* Let's build hash */ db_r->pr_hash = apr_hash_make(db_r->p); /* Dead properties */ for (dead_prop = db_r->pr; dead_prop; dead_prop = dead_prop->next) { const char *ns = dbms_get_ns(db_r, dead_prop->m_ns_id); const char *key = dav_repos_build_ns_name_key(ns, dead_prop->m_propname, db_r->p); apr_hash_set(db_r->pr_hash, key, APR_HASH_KEY_STRING, dead_prop); //DBG2("KEY: [%s]%s", key, dead_prop->m_propname); } } /* Build live property */ void dav_repos_build_lpr_hash(dav_repos_resource *db_r) { const char *s; dav_repos_server_conf *dsc = NULL; /* an HTTP-date can be 29 chars plus a null term */ /* a 64-bit size can be 20 chars plus a null term */ char date[DAV_TIMEBUF_SIZE];; TRACE(); dsc = dav_repos_get_server_conf(db_r->r->server); if (!dsc) return; /* Let's build hash */ db_r->lpr_hash = apr_hash_make(db_r->p); /* is directory */ if (db_r->m_resource_type == dav_repos_COLLECTION) { apr_hash_set(db_r->lpr_hash, "resourcetype", APR_HASH_KEY_STRING, ""); } else { apr_hash_set(db_r->lpr_hash, "resourcetype", APR_HASH_KEY_STRING, ""); } s = apr_psprintf(db_r->p, "%" APR_INT64_T_FMT "", db_r->m_get_content_length); apr_hash_set(db_r->lpr_hash, "getcontentlength", APR_HASH_KEY_STRING, s); DBG1("dav_repos_build_lpr_hash:db_r->m_creation_date= %" APR_INT64_T_FMT "", db_r->m_creation_date); /* set live properties */ dav_repos_format_time(DAV_STYLE_ISO8601, db_r->m_creation_date, date); apr_hash_set(db_r->lpr_hash, "creationdate", APR_HASH_KEY_STRING, apr_pstrdup(db_r->p, date)); DBG1("dav_repos_build_lpr_hash:db_r->m_get_lastmodified = %" APR_INT64_T_FMT "", db_r->m_get_lastmodified); dav_repos_format_time(DAV_STYLE_RFC822, db_r->m_get_lastmodified, date); apr_hash_set(db_r->lpr_hash, "getlastmodified", APR_HASH_KEY_STRING, apr_pstrdup(db_r->p, date)); apr_hash_set(db_r->lpr_hash, "getetag", APR_HASH_KEY_STRING, dav_repos_getetag_dbr(db_r)); apr_hash_set(db_r->lpr_hash, "getcontenttype", APR_HASH_KEY_STRING, db_r->m_get_content_type ? db_r->m_get_content_type : ""); DBG2("dav_repos_build_lpr_hash:db_r->m_host_name=%s dsc->host_name=%s", db_r->m_host_name, dsc->host_name); /* CHG 2010-07-02 huibong * NetCache 상에서 PROFIND 에 대한 결과 요청시 원본 host_name 정보를 무조건 입력해서 보낼도록 수정 * 기존 양방향과 호환을 위해 User-Agent String 상에 NetCache 가 존재하는 경우에만 처리하도록 함. * 양방향에서 현 장비에 해당 파일이 존재하는 경우 Connection 재사용을 위해 Host Name 정보를 보내지 않음. */ /* apr_hash_set(db_r->lpr_hash, "source", APR_HASH_KEY_STRING, (db_r->m_host_name && strcmp(db_r->m_host_name, dsc->host_name) ? apr_pstrdup(db_r->p, db_r->m_host_name) : "")); */ if( db_r->m_host_name != NULL ) // 원본 파일에 대한 Host Name 정보가 존재하는 경우 { // 원본 Host Name 과 현재 장비의 Host Name 이 틀린 경우 => Host Name 정보 전달. if( strcmp(db_r->m_host_name, dsc->host_name) != 0 ) { apr_hash_set(db_r->lpr_hash, "source", APR_HASH_KEY_STRING, apr_pstrdup(db_r->p, db_r->m_host_name)); } else { // NetCache Agent 인지를 확인하기 위해 PROFPIND Header 의 User-Agent 정보 검사. const char * userAgent = NULL; userAgent = apr_table_get( db_r->r->headers_in, "User-Agent"); if( userAgent != NULL && (strncmp(userAgent, "NetCache", 8)==0) ) { // User-Agent 정보가 NetCache 로 시작하는 경우 -> 무조건 Host Name 정보를 입력하여 전달. //ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,"dav_repos_build_lpr_hash: User-Agent[%s] source[%s]", userAgent, db_r->m_host_name); apr_hash_set(db_r->lpr_hash, "source", APR_HASH_KEY_STRING, apr_pstrdup(db_r->p, db_r->m_host_name)); } else { // 기존 양방향 Client 인 경우 Host Name 정보와 현재 장비가 동일한 하면 => 빈 문자열 전달. apr_hash_set(db_r->lpr_hash, "source", APR_HASH_KEY_STRING, ""); } } } else { // 원본 파일에 대한 Host Name 정보가 존재하지 않는 경우 빈값을 전달처리 apr_hash_set(db_r->lpr_hash, "source", APR_HASH_KEY_STRING, ""); } // 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery) apr_hash_set(db_r->lpr_hash, "getcontentlanguage", APR_HASH_KEY_STRING, ""); } /*# FIXME : This is a insert lock info for search and prop. ** Do we really need a lock info when we search ? ** Then we should make params in search semewhere. ** ** Need to move find_live and live props */ dav_error *dav_repos_insert_lock_prop(const dav_walk_params * params, dav_repos_resource * db_r) { dav_error *err; dav_resource *resource = NULL; //dav_walker_ctx *ctx = params->walk_ctx; TRACE(); /* Initilize */ // 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery) if (params->lockdb != NULL) { dav_lock *locks = NULL; /* * FIXME : We don't have a resource here * Our lock hook will use only uri and exist filed in resource */ resource = apr_pcalloc(db_r->p, sizeof(*resource)); resource->exists = 1; resource->uri = db_r->m_fake_uri; if ((err = dav_lock_query(params->lockdb, resource, &locks)) != NULL) { return dav_push_error(db_r->p, err->status, 0, "DAV:lockdiscovery could not be " "determined due to a problem fetching " "the locks for this resource.", err); } /* fast-path the no-locks case */ if (locks) { /* ** This may modify the buffer. value may point to ** wb_lock.pbuf or a string constant. */ // 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery) //db_r->m_lock_discovery = dav_lock_get_activelock(ctx->r, locks, NULL); /* Do we need strdup here */ /* db_r->lockdiscovery = apr_pstrdup(db_r->p, wb_lock.buf); */ } /* * Get supported lock info * Our lock hook will not use resource though. */ // 2014.07.09 : 사용되지 않는 컬럼 정리(get_content_language,get_etag,supported_lock,lock_discovery) } return NULL; } /* make sure the pathname does not have a trailing "/" */ void dav_repos_no_trail(char *str) { int len = strlen(str); while (len > 1 && str[len - 1] == '/') { str[len - 1] = '\0'; len = strlen(str); } TRACE(); } int dav_repos_remove_unsafe_chars(const char *pOld, char *pNew) { int nCount = 0; if((pOld == NULL) || (pNew == NULL)) { return -1; } while(*pOld != '\0') { if((*pOld == '\'') || (*pOld == '\\')) { pOld++; } else { pNew[nCount++] = *pOld++; } } pNew[nCount] = '\0'; return 1; } int dav_repos_replace_unsafe_chars(const char *pOld, char *pNew) { if ((pOld == NULL) || (pNew == NULL)) { return -1; } char const * const pattern = "'"; char const * const replacement = "''"; size_t const replen = strlen(replacement); size_t const patlen = strlen(pattern); const char * oriptr; const char * patloc; memset(pNew, 0x00, sizeof(*pNew)); for (oriptr = pOld; (patloc = strstr(oriptr, pattern)); oriptr = patloc + patlen) { size_t const skplen = patloc - oriptr; // copy the section until the occurence of the pattern strncpy(pNew, oriptr, skplen); pNew += skplen; // copy the replacement strncpy(pNew, replacement, replen); pNew += replen; } // copy the rest of the string. strcpy(pNew, oriptr); return 1; } int dav_repos_restore_unsafe_chars(const char *pOld, char *pNew) { if ((pOld == NULL) || (pNew == NULL)) { return -1; } char const * const pattern = "''"; char const * const replacement = "'"; size_t const replen = strlen(replacement); size_t const patlen = strlen(pattern); const char * oriptr; const char * patloc; memset(pNew, 0x00, sizeof(*pNew)); for (oriptr = pOld; (patloc = strstr(oriptr, pattern)); oriptr = patloc + patlen) { size_t const skplen = patloc - oriptr; // copy the section until the occurence of the pattern strncpy(pNew, oriptr, skplen); pNew += skplen; // copy the replacement strncpy(pNew, replacement, replen); pNew += replen; } // copy the rest of the string. strcpy(pNew, oriptr); return 1; } int dav_repos_replace_multi_slash_chars(const char *pOld, char *pNew) { int nCount = 0; int slash_detect = 0; if ((pOld == NULL) || (pNew == NULL)) { return -1; } while (*pOld != '\0') { if (*pOld == '/') { if (slash_detect == 0) { slash_detect = 1; } else { pOld++; continue; } } else { slash_detect = 0; } pNew[nCount++] = *pOld++; } pNew[nCount] = '\0'; return 1; } #ifdef __OPENDISK_SOLUTION__ int dav_repos_change_resource_type(int resource_type) { if (resource_type >= dav_repos_RECYCLE) { return (resource_type - dav_repos_RECYCLE); } else if (resource_type >= dav_repos_SHARE) { return (resource_type - dav_repos_SHARE); } return resource_type; } #endif #define PRIVATE_KEY "gE\x8bk\xc6\x23{2i\x98> 5)) + k1; // v1 += (v0 << 4) + (k2 ^ v0) + (sum ^ (v0 >> 5)) + k3; /* end cycle */ // } // v[0] = v0; v[1] = v1; //} static void __tea_decrypt(unsigned int *v, unsigned int *k) { unsigned int v0 = v[0], v1 = v[1], sum = 0xC6EF3720, i; /* set up */ unsigned int delta = 0x9e3779b9; /* a key schedule constant */ unsigned int k0 = k[0], k1 = k[1], k2 = k[2], k3 = k[3]; /* cache key */ for (i = 0; i < 32; i++) { /* basic cycle start */ v1 -= (v0 << 4) + (k2 ^ v0) + (sum ^ (v0 >> 5)) + k3; v0 -= (v1 << 4) + (k0 ^ v1) + (sum ^ (v1 >> 5)) + k1; sum -= delta; /* end cycle */ } v[0] = v0; v[1] = v1; } /* static void tea_encrypt(char *buf, int len) { int __len = (len + 7) >> 3; int i; //char *key = PRIVATE_KEY; for (i = 0; i < __len; i++) { __tea_encrypt((((unsigned int *)buf) + (i << 1)), (unsigned int *)PRIVATE_KEY); } } */ void tea_decrypt(char *buf, int len) { int __len = (len + 7) >> 3; int i; for (i = 0; i < __len; i++) { __tea_decrypt((((unsigned int *)buf) + (i << 1)), (unsigned int *)PRIVATE_KEY); } } int file_trylock(int fd) { struct flock _lock; memset( &_lock, 0, sizeof(struct flock) ); _lock.l_type = F_WRLCK; _lock.l_start = 0; _lock.l_whence = SEEK_SET; _lock.l_len = 0; return fcntl(fd, F_SETLK, &_lock); } int file_unlock(int fd) { struct flock _lock; memset( &_lock, 0, sizeof(struct flock) ); _lock.l_type = F_UNLCK; _lock.l_start = 0; _lock.l_whence = SEEK_SET; _lock.l_len = 0; return fcntl(fd, F_SETLK, &_lock); } /* apache version 업에 따른 apr_dbd_get_row 처리 방법 변경 */ int solbox_apr_dbd_get_row(const apr_dbd_driver_t *driver, apr_pool_t *pool, apr_dbd_results_t *res, apr_dbd_row_t **row, int rownum) { DBG1("solbox_apr_dbd_get_row #1 = %s", APU_VERSION_STRING); /* apu vsrsion 1.3.0 부터 rowunm counting 1부터 시작*/ if(rownum >= 0 && strcmp(APU_VERSION_STRING, "1.3.0") >= 0) { return apr_dbd_get_row(driver, pool, res, row, rownum+1); } else { return apr_dbd_get_row(driver, pool, res, row, rownum); } return -1; } dav_error* solbox_dav_new_error(apr_pool_t *p, int status, int error_id, const char *desc) { #if AP_SERVER_MAJORVERSION_NUMBER > 2 || AP_SERVER_MINORVERSION_NUMBER >= 3 return dav_new_error(p, status, error_id, 0, desc); #else // 2.2.x return dav_new_error(p, status, error_id, desc); #endif // 2.3 over } const char *dav_http_scheme(const request_rec *r) { /* * The http module shouldn't return anything other than * "http" (the default) or "https". */ if (r->server->server_scheme && (strcmp(r->server->server_scheme, "https") == 0)) return "https"; return "http"; }