Merge pull request #53 from s3fs-fuse/sse-c

Support for SSE-C #39
This commit is contained in:
Takeshi Nakatani 2014-09-07 22:31:33 +09:00
commit ae4ae88b6d
8 changed files with 487 additions and 102 deletions

View File

@ -71,9 +71,13 @@ this option can not be specified with use_sse.
(can specify use_rrs=1 for old version) (can specify use_rrs=1 for old version)
.TP .TP
\fB\-o\fR use_sse (default is disable) \fB\-o\fR use_sse (default is disable)
use Amazon's Server Site Encryption. use Amazon<6F>fs Server-Site Encryption or Server-Side Encryption with Customer-Provided Encryption Keys.
this option can not be specified with use_rrs. this option can not be specified with use_rrs. specifying only "use_sse" or "use_sse=1" enables Server-Side Encryption.(use_sse=1 for old version)
(can specify use_sse=1 for old version) specifying this option with file path which has some SSE-C secret key enables Server-Side Encryption with Customer-Provided Encryption Keys.(use_sse=file)
the file must be 600 permission. the file can have some lines, each line is one SSE-C key. the first line in file is used as Customer-Provided Encryption Keys for uploading and change headers etc.
if there are some keys after first line, those are used downloading object which are encripted by not first key.
so that, you can keep all SSE-C keys in file, that is SSE-C key history.
if AWSSSECKEYS environment is set, you can set SSE-C key instead of this option.
.TP .TP
\fB\-o\fR passwd_file (default="") \fB\-o\fR passwd_file (default="")
specify the path to the password file, which which takes precedence over the password in $HOME/.passwd-s3fs and /etc/passwd-s3fs specify the path to the password file, which which takes precedence over the password in $HOME/.passwd-s3fs and /etc/passwd-s3fs

View File

@ -51,6 +51,63 @@
using namespace std; using namespace std;
//-------------------------------------------------------------------
// Utilities
//-------------------------------------------------------------------
// [TODO]
// This function uses tempolary file, but should not use it.
// For not using it, we implement function in each auth file(openssl, nss. gnutls).
//
static bool make_md5_from_string(const char* pstr, string& md5)
{
if(!pstr || '\0' == pstr[0]){
DPRN("Parameter is wrong.");
return false;
}
FILE* fp;
if(NULL == (fp = tmpfile())){
FPRN("Could not make tmpfile.");
return false;
}
size_t length = strlen(pstr);
if(length != fwrite(pstr, sizeof(char), length, fp)){
FPRN("Failed to write tmpfile.");
fclose(fp);
return false;
}
int fd;
if(0 != fflush(fp) || 0 != fseek(fp, 0L, SEEK_SET) || -1 == (fd = fileno(fp))){
FPRN("Failed to make MD5.");
fclose(fp);
return false;
}
// base64 md5
md5 = s3fs_get_content_md5(fd);
if(0 == md5.length()){
FPRN("Failed to make MD5.");
fclose(fp);
return false;
}
fclose(fp);
return true;
}
#if 0 // noused
static string tolower_header_name(const char* head)
{
string::size_type pos;
string name = head;
string value("");
if(string::npos != (pos = name.find(':'))){
value= name.substr(pos);
name = name.substr(0, pos);
}
name = lower(name);
name += value;
return name;
}
#endif
//------------------------------------------------------------------- //-------------------------------------------------------------------
// Class BodyData // Class BodyData
//------------------------------------------------------------------- //-------------------------------------------------------------------
@ -154,6 +211,7 @@ int S3fsCurl::retries = 3; // default
bool S3fsCurl::is_public_bucket = false; bool S3fsCurl::is_public_bucket = false;
string S3fsCurl::default_acl = "private"; string S3fsCurl::default_acl = "private";
bool S3fsCurl::is_use_rrs = false; bool S3fsCurl::is_use_rrs = false;
sseckeylist_t S3fsCurl::sseckeys;
bool S3fsCurl::is_use_sse = false; bool S3fsCurl::is_use_sse = false;
bool S3fsCurl::is_content_md5 = false; bool S3fsCurl::is_content_md5 = false;
bool S3fsCurl::is_verbose = false; bool S3fsCurl::is_verbose = false;
@ -684,6 +742,126 @@ bool S3fsCurl::SetUseRrs(bool flag)
return old; return old;
} }
bool S3fsCurl::PushbackSseKeys(string& onekey)
{
onekey = trim(onekey);
if(0 == onekey.size()){
return false;
}
if('#' == onekey[0]){
return false;
}
// make base64
char* pbase64_key;
if(NULL == (pbase64_key = s3fs_base64((unsigned char*)onekey.c_str(), onekey.length()))){
FPRN("Failed to convert base64 from sse-c key %s", onekey.c_str());
return false;
}
string base64_key = pbase64_key;
free(pbase64_key);
// make MD5
string strMd5;
if(!make_md5_from_string(onekey.c_str(), strMd5)){
FPRN("Could not make MD5 from SSE-C keys(%s).", onekey.c_str());
return false;
}
// mapped MD5 = SSE Key
sseckeymap_t md5map;
md5map.clear();
md5map[strMd5] = base64_key;
S3fsCurl::sseckeys.push_back(md5map);
return true;
}
bool S3fsCurl::SetSseKeys(const char* filepath)
{
if(!filepath){
DPRN("SSE-C keys filepath is empty.");
return false;
}
S3fsCurl::sseckeys.clear();
ifstream ssefs(filepath);
if(!ssefs.good()){
FPRN("Could not open SSE-C keys file(%s).", filepath);
return false;
}
string line;
while(getline(ssefs, line)){
S3fsCurl::PushbackSseKeys(line);
}
if(0 == S3fsCurl::sseckeys.size()){
FPRN("There is no SSE Key in file(%s).", filepath);
return false;
}
return true;
}
bool S3fsCurl::LoadEnvSseKeys(void)
{
char* envkeys = getenv("AWSSSECKEYS");
if(NULL == envkeys){
return false;
}
S3fsCurl::sseckeys.clear();
istringstream fullkeys(envkeys);
string onekey;
while(getline(fullkeys, onekey, ':')){
S3fsCurl::PushbackSseKeys(onekey);
}
if(0 == S3fsCurl::sseckeys.size()){
FPRN("There is no SSE Key in environment(AWSSSECKEYS=%s).", envkeys);
return false;
}
return true;
}
//
// If md5 is empty, returns first(current) sse key.
//
bool S3fsCurl::GetSseKey(string& md5, string& ssekey)
{
for(sseckeylist_t::const_iterator iter = S3fsCurl::sseckeys.begin(); iter != S3fsCurl::sseckeys.end(); iter++){
if(0 == md5.length() || md5 == (*iter).begin()->first){
md5 = iter->begin()->first;
ssekey = iter->begin()->second;
return true;
}
}
return false;
}
bool S3fsCurl::GetSseKeyMd5(int pos, string& md5)
{
if(pos < 0){
return false;
}
if(S3fsCurl::sseckeys.size() <= static_cast<size_t>(pos)){
return false;
}
int cnt = 0;
for(sseckeylist_t::const_iterator iter = S3fsCurl::sseckeys.begin(); iter != S3fsCurl::sseckeys.end(); iter++, cnt++){
if(pos == cnt){
md5 = iter->begin()->first;
return true;
}
}
return false;
}
int S3fsCurl::GetSseKeyCount(void)
{
return S3fsCurl::sseckeys.size();
}
bool S3fsCurl::IsSseCustomMode(void)
{
return (0 < S3fsCurl::sseckeys.size());
}
bool S3fsCurl::SetUseSse(bool flag) bool S3fsCurl::SetUseSse(bool flag)
{ {
bool old = S3fsCurl::is_use_sse; bool old = S3fsCurl::is_use_sse;
@ -806,7 +984,7 @@ S3fsCurl* S3fsCurl::UploadMultipartPostRetryCallback(S3fsCurl* s3fscurl)
return newcurl; return newcurl;
} }
int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse_flg) int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta, int fd)
{ {
int result; int result;
string upload_id; string upload_id;
@ -832,7 +1010,7 @@ int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta,
return -errno; return -errno;
} }
if(0 != (result = s3fscurl.PreMultipartPostRequest(tpath, meta, upload_id, ow_sse_flg))){ if(0 != (result = s3fscurl.PreMultipartPostRequest(tpath, meta, upload_id, false))){
close(fd2); close(fd2);
return result; return result;
} }
@ -911,7 +1089,7 @@ S3fsCurl* S3fsCurl::ParallelGetObjectRetryCallback(S3fsCurl* s3fscurl)
// duplicate request(setup new curl object) // duplicate request(setup new curl object)
S3fsCurl* newcurl = new S3fsCurl(s3fscurl->IsUseAhbe()); S3fsCurl* newcurl = new S3fsCurl(s3fscurl->IsUseAhbe());
if(0 != (result = newcurl->PreGetObjectRequest( if(0 != (result = newcurl->PreGetObjectRequest(
s3fscurl->path.c_str(), s3fscurl->partdata.fd, s3fscurl->partdata.startpos, s3fscurl->partdata.size))){ s3fscurl->path.c_str(), s3fscurl->partdata.fd, s3fscurl->partdata.startpos, s3fscurl->partdata.size, s3fscurl->b_ssekey_md5))){
DPRN("failed downloading part setup(%d)", result); DPRN("failed downloading part setup(%d)", result);
delete newcurl; delete newcurl;
return NULL;; return NULL;;
@ -925,6 +1103,12 @@ int S3fsCurl::ParallelGetObjectRequest(const char* tpath, int fd, off_t start, s
{ {
FPRNNN("[tpath=%s][fd=%d]", SAFESTRPTR(tpath), fd); FPRNNN("[tpath=%s][fd=%d]", SAFESTRPTR(tpath), fd);
string sseckeymd5("");
char* psseckeymd5;
if(NULL != (psseckeymd5 = get_object_sseckey_md5(tpath))){
sseckeymd5 = psseckeymd5;
free(psseckeymd5);
}
int result = 0; int result = 0;
ssize_t remaining_bytes; ssize_t remaining_bytes;
@ -945,7 +1129,7 @@ int S3fsCurl::ParallelGetObjectRequest(const char* tpath, int fd, off_t start, s
// s3fscurl sub object // s3fscurl sub object
S3fsCurl* s3fscurl_para = new S3fsCurl(); S3fsCurl* s3fscurl_para = new S3fsCurl();
if(0 != (result = s3fscurl_para->PreGetObjectRequest(tpath, fd, (start + size - remaining_bytes), chunk))){ if(0 != (result = s3fscurl_para->PreGetObjectRequest(tpath, fd, (start + size - remaining_bytes), chunk, sseckeymd5))){
DPRN("failed downloading part setup(%d)", result); DPRN("failed downloading part setup(%d)", result);
delete s3fscurl_para; delete s3fscurl_para;
return result; return result;
@ -1053,7 +1237,8 @@ bool S3fsCurl::CheckIAMCredentialUpdate(void)
S3fsCurl::S3fsCurl(bool ahbe) : S3fsCurl::S3fsCurl(bool ahbe) :
hCurl(NULL), path(""), base_path(""), saved_path(""), url(""), requestHeaders(NULL), hCurl(NULL), path(""), base_path(""), saved_path(""), url(""), requestHeaders(NULL),
bodydata(NULL), headdata(NULL), LastResponseCode(-1), postdata(NULL), postdata_remaining(0), is_use_ahbe(ahbe), bodydata(NULL), headdata(NULL), LastResponseCode(-1), postdata(NULL), postdata_remaining(0), is_use_ahbe(ahbe),
retry_count(0), b_infile(NULL), b_postdata(NULL), b_postdata_remaining(0), b_partdata_startpos(0), b_partdata_size(0) retry_count(0), b_infile(NULL), b_postdata(NULL), b_postdata_remaining(0), b_partdata_startpos(0), b_partdata_size(0),
b_ssekey_pos(-1), b_ssekey_md5("")
{ {
type = REQTYPE_UNSET; type = REQTYPE_UNSET;
} }
@ -1728,12 +1913,38 @@ int S3fsCurl::GetIAMCredentials(void)
return result; return result;
} }
//
// If md5 is empty, build by first(current) sse key
//
bool S3fsCurl::AddSseKeyRequestHead(string& md5, bool is_copy)
{
if(!S3fsCurl::IsSseCustomMode()){
// Nothing to do
return true;
}
string sseckey;
if(S3fsCurl::GetSseKey(md5, sseckey)){
if(is_copy){
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-copy-source-server-side-encryption-customer-algorithm:AES256");
requestHeaders = curl_slist_sort_insert(requestHeaders, string("x-amz-copy-source-server-side-encryption-customer-key:" + sseckey).c_str());
requestHeaders = curl_slist_sort_insert(requestHeaders, string("x-amz-copy-source-server-side-encryption-customer-key-md5:" + md5).c_str());
}else{
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption-customer-algorithm:AES256");
requestHeaders = curl_slist_sort_insert(requestHeaders, string("x-amz-server-side-encryption-customer-key:" + sseckey).c_str());
requestHeaders = curl_slist_sort_insert(requestHeaders, string("x-amz-server-side-encryption-customer-key-md5:" + md5).c_str());
}
}
return true;
}
// //
// tpath : target path for head request // tpath : target path for head request
// bpath : saved into base_path // bpath : saved into base_path
// savedpath : saved into saved_path // savedpath : saved into saved_path
// ssekey_pos : -1 means "not use sse", 0 - X means "use sseckey" and "sseckey position".
// sseckey position 0 is latest key.
// //
bool S3fsCurl::PreHeadRequest(const char* tpath, const char* bpath, const char* savedpath) bool S3fsCurl::PreHeadRequest(const char* tpath, const char* bpath, const char* savedpath, int ssekey_pos)
{ {
FPRNINFO("[tpath=%s][bpath=%s][save=%s]", SAFESTRPTR(tpath), SAFESTRPTR(bpath), SAFESTRPTR(savedpath)); FPRNINFO("[tpath=%s][bpath=%s][save=%s]", SAFESTRPTR(tpath), SAFESTRPTR(bpath), SAFESTRPTR(savedpath));
@ -1759,6 +1970,15 @@ bool S3fsCurl::PreHeadRequest(const char* tpath, const char* bpath, const char*
string date = get_date(); string date = get_date();
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
requestHeaders = curl_slist_sort_insert(requestHeaders, "Content-Type: "); requestHeaders = curl_slist_sort_insert(requestHeaders, "Content-Type: ");
if(0 <= ssekey_pos && S3fsCurl::IsSseCustomMode()){
string md5;
if(!S3fsCurl::GetSseKeyMd5(ssekey_pos, md5) || !AddSseKeyRequestHead(md5, false)){
DPRN("Failed to set SSE-C headers for md5(%s).", md5.c_str());
}
}
b_ssekey_pos = ssekey_pos;
if(!S3fsCurl::IsPublicBucket()){ if(!S3fsCurl::IsPublicBucket()){
requestHeaders = curl_slist_sort_insert( requestHeaders = curl_slist_sort_insert(
requestHeaders, requestHeaders,
@ -1782,32 +2002,53 @@ bool S3fsCurl::PreHeadRequest(const char* tpath, const char* bpath, const char*
int S3fsCurl::HeadRequest(const char* tpath, headers_t& meta) int S3fsCurl::HeadRequest(const char* tpath, headers_t& meta)
{ {
int result; int result = -1;
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath)); FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
if(!PreHeadRequest(tpath)){ if(S3fsCurl::IsSseCustomMode()){
return -1; // SSE-C mode, check all sse-c key at first
} int pos;
// Requests for(pos = 0; static_cast<size_t>(pos) < S3fsCurl::sseckeys.size(); pos++){
if(0 != (result = RequestPerform())){ if(0 != pos && !DestroyCurlHandle()){
return result; return result;
} }
if(!PreHeadRequest(tpath, NULL, NULL, pos)){
return result;
}
if(0 == (result = RequestPerform())){
break;
}
}
if(S3fsCurl::sseckeys.size() <= static_cast<size_t>(pos)){
// If sse-c mode is enable, s3fs fails to get head request for normal and sse object.
// So try to get head without sse-c header.
if(!DestroyCurlHandle() || !PreHeadRequest(tpath, NULL, NULL, -1) || 0 != (result = RequestPerform())){
return result;
}
}
}else{
// Not sse-c mode
if(!PreHeadRequest(tpath) || 0 != (result = RequestPerform())){
return result;
}
}
// file exists in s3 // file exists in s3
// fixme: clean this up. // fixme: clean this up.
meta.clear(); meta.clear();
for(headers_t::iterator iter = responseHeaders.begin(); iter != responseHeaders.end(); ++iter){ for(headers_t::iterator iter = responseHeaders.begin(); iter != responseHeaders.end(); ++iter){
string key = (*iter).first; string key = (*iter).first;
string value = (*iter).second; string value = (*iter).second;
if(key == "Content-Type"){ if(0 == strcasecmp(key.c_str(), "Content-Type")){
meta[key] = value; meta[key] = value;
}else if(key == "Content-Length"){ }else if(0 == strcasecmp(key.c_str(), "Content-Length")){
meta[key] = value; meta[key] = value;
}else if(key == "ETag"){ }else if(0 == strcasecmp(key.c_str(), "ETag")){
meta[key] = value; meta[key] = value;
}else if(key == "Last-Modified"){ }else if(0 == strcasecmp(key.c_str(), "Last-Modified")){
meta[key] = value; meta[key] = value;
}else if(key.substr(0, 5) == "x-amz"){ }else if(0 == strcasecmp(key.substr(0, 5).c_str(), "x-amz")){
meta[key] = value; meta[key] = value;
}else{ }else{
// Check for upper case // Check for upper case
@ -1820,7 +2061,7 @@ int S3fsCurl::HeadRequest(const char* tpath, headers_t& meta)
return 0; return 0;
} }
int S3fsCurl::PutHeadRequest(const char* tpath, headers_t& meta, bool ow_sse_flg) int S3fsCurl::PutHeadRequest(const char* tpath, headers_t& meta, bool is_copy)
{ {
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath)); FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
@ -1848,18 +2089,24 @@ int S3fsCurl::PutHeadRequest(const char* tpath, headers_t& meta, bool ow_sse_flg
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){ for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
string key = (*iter).first; string key = (*iter).first;
string value = (*iter).second; string value = (*iter).second;
if(key == "Content-Type"){ if(0 == strcasecmp(key.c_str(), "Content-Type")){
ContentType = value; ContentType = value;
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(key.substr(0,9) == "x-amz-acl"){ }else if(0 == strcasecmp(key.substr(0,9).c_str(), "x-amz-acl")){
// not set value, but after set it. // not set value, but after set it.
}else if(key.substr(0,10) == "x-amz-meta"){ }else if(0 == strcasecmp(key.substr(0,10).c_str(), "x-amz-meta")){
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(key == "x-amz-copy-source"){ }else if(0 == strcasecmp(key.c_str(), "x-amz-copy-source")){
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(!ow_sse_flg && key == "x-amz-server-side-encryption"){
// If ow_sse_flg is false, SSE inherit from meta.
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption")){
// skip this header, because this header is specified after logic.
}else if(0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption-customer-algorithm")){
// skip this header, because this header is specified with "x-amz-...-customer-key-md5".
}else if(is_copy && 0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption-customer-key-md5")){
// Only copy mode.
if(!AddSseKeyRequestHead(value, is_copy)){
DPRNNN("Failed to insert sse(-c) header.");
}
} }
} }
// "x-amz-acl", rrs, sse // "x-amz-acl", rrs, sse
@ -1867,8 +2114,13 @@ int S3fsCurl::PutHeadRequest(const char* tpath, headers_t& meta, bool ow_sse_flg
if(S3fsCurl::is_use_rrs){ if(S3fsCurl::is_use_rrs){
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-storage-class:REDUCED_REDUNDANCY"); requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-storage-class:REDUCED_REDUNDANCY");
} }
if(ow_sse_flg && S3fsCurl::is_use_sse){ if(S3fsCurl::is_use_sse){
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption:AES256"); requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption:AES256");
}else if(S3fsCurl::IsSseCustomMode()){
string md5;
if(!AddSseKeyRequestHead(md5, false)){
DPRNNN("Failed to insert sse(-c) header.");
}
} }
if(is_use_ahbe){ if(is_use_ahbe){
// set additional header by ahbe conf // set additional header by ahbe conf
@ -1900,7 +2152,7 @@ int S3fsCurl::PutHeadRequest(const char* tpath, headers_t& meta, bool ow_sse_flg
return result; return result;
} }
int S3fsCurl::PutRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse_flg) int S3fsCurl::PutRequest(const char* tpath, headers_t& meta, int fd)
{ {
struct stat st; struct stat st;
FILE* file = NULL; FILE* file = NULL;
@ -1953,16 +2205,19 @@ int S3fsCurl::PutRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){ for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
string key = (*iter).first; string key = (*iter).first;
string value = (*iter).second; string value = (*iter).second;
if(key == "Content-Type"){ if(0 == strcasecmp(key.c_str(), "Content-Type")){
ContentType = value; ContentType = value;
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(key.substr(0,9) == "x-amz-acl"){ }else if(0 == strcasecmp(key.substr(0,9).c_str(), "x-amz-acl")){
// not set value, but after set it. // not set value, but after set it.
}else if(key.substr(0,10) == "x-amz-meta"){ }else if(0 == strcasecmp(key.substr(0,10).c_str(), "x-amz-meta")){
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(!ow_sse_flg && key == "x-amz-server-side-encryption"){
// If ow_sse_flg is false, SSE inherit from meta.
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption")){
// skip this header, because this header is specified after logic.
}else if(0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption-customer-algorithm")){
// skip this header, because this header is specified after logic.
}else if(0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption-customer-key-md5")){
// skip this header, because this header is specified after logic.
} }
} }
// "x-amz-acl", rrs, sse // "x-amz-acl", rrs, sse
@ -1970,8 +2225,13 @@ int S3fsCurl::PutRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse
if(S3fsCurl::is_use_rrs){ if(S3fsCurl::is_use_rrs){
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-storage-class:REDUCED_REDUNDANCY"); requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-storage-class:REDUCED_REDUNDANCY");
} }
if(ow_sse_flg && S3fsCurl::is_use_sse){ if(S3fsCurl::is_use_sse){
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption:AES256"); requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption:AES256");
}else if(S3fsCurl::IsSseCustomMode()){
string md5;
if(!AddSseKeyRequestHead(md5, false)){
DPRNNN("Failed to insert sse(-c) header.");
}
} }
if(is_use_ahbe){ if(is_use_ahbe){
// set additional header by ahbe conf // set additional header by ahbe conf
@ -2011,7 +2271,7 @@ int S3fsCurl::PutRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse
return result; return result;
} }
int S3fsCurl::PreGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size) int S3fsCurl::PreGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size, string& ssekeymd5)
{ {
FPRNNN("[tpath=%s][start=%jd][size=%zd]", SAFESTRPTR(tpath), (intmax_t)start, size); FPRNNN("[tpath=%s][start=%jd][size=%zd]", SAFESTRPTR(tpath), (intmax_t)start, size);
@ -2041,6 +2301,11 @@ int S3fsCurl::PreGetObjectRequest(const char* tpath, int fd, off_t start, ssize_
range += str(start + size - 1); range += str(start + size - 1);
requestHeaders = curl_slist_sort_insert(requestHeaders, range.c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, range.c_str());
} }
if(0 < ssekeymd5.length()){
if(!AddSseKeyRequestHead(ssekeymd5, false)){
DPRNNN("Failed to insert sse(-c) header.");
}
}
if(!S3fsCurl::IsPublicBucket()){ if(!S3fsCurl::IsPublicBucket()){
requestHeaders = curl_slist_sort_insert( requestHeaders = curl_slist_sort_insert(
@ -2063,6 +2328,7 @@ int S3fsCurl::PreGetObjectRequest(const char* tpath, int fd, off_t start, ssize_
partdata.size = size; partdata.size = size;
b_partdata_startpos = start; b_partdata_startpos = start;
b_partdata_size = size; b_partdata_size = size;
b_ssekey_md5 = ssekeymd5;
type = REQTYPE_GET; type = REQTYPE_GET;
@ -2078,7 +2344,13 @@ int S3fsCurl::GetObjectRequest(const char* tpath, int fd, off_t start, ssize_t s
if(!tpath){ if(!tpath){
return -1; return -1;
} }
if(0 != (result = PreGetObjectRequest(tpath, fd, start, size))){ string sseckeymd5("");
char* psseckeymd5;
if(NULL != (psseckeymd5 = get_object_sseckey_md5(tpath))){
sseckeymd5 = psseckeymd5;
free(psseckeymd5);
}
if(0 != (result = PreGetObjectRequest(tpath, fd, start, size, sseckeymd5))){
return result; return result;
} }
@ -2187,7 +2459,7 @@ int S3fsCurl::ListBucketRequest(const char* tpath, const char* query)
// Date: Mon, 1 Nov 2010 20:34:56 GMT // Date: Mon, 1 Nov 2010 20:34:56 GMT
// Authorization: AWS VGhpcyBtZXNzYWdlIHNpZ25lZCBieSBlbHZpbmc= // Authorization: AWS VGhpcyBtZXNzYWdlIHNpZ25lZCBieSBlbHZpbmc=
// //
int S3fsCurl::PreMultipartPostRequest(const char* tpath, headers_t& meta, string& upload_id, bool ow_sse_flg) int S3fsCurl::PreMultipartPostRequest(const char* tpath, headers_t& meta, string& upload_id, bool is_copy)
{ {
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath)); FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
@ -2220,13 +2492,19 @@ int S3fsCurl::PreMultipartPostRequest(const char* tpath, headers_t& meta, string
string key = (*iter).first; string key = (*iter).first;
string value = (*iter).second; string value = (*iter).second;
if(key.substr(0,9) == "x-amz-acl"){ if(0 == strcasecmp(key.substr(0,9).c_str(), "x-amz-acl")){
// not set value, but after set it. // not set value, but after set it.
}else if(key.substr(0,10) == "x-amz-meta"){ }else if(0 == strcasecmp(key.substr(0,10).c_str(), "x-amz-meta")){
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(!ow_sse_flg && key == "x-amz-server-side-encryption"){
// If ow_sse_flg is false, SSE inherit from meta.
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption")){
// skip this header, because this header is specified after logic.
}else if(0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption-customer-algorithm")){
// skip this header, because this header is specified with "x-amz-...-customer-key-md5".
}else if(is_copy && 0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption-customer-key-md5")){
// Only copy mode.
if(!AddSseKeyRequestHead(value, is_copy)){
DPRNNN("Failed to insert sse(-c) header.");
}
} }
} }
// "x-amz-acl", rrs, sse // "x-amz-acl", rrs, sse
@ -2234,8 +2512,13 @@ int S3fsCurl::PreMultipartPostRequest(const char* tpath, headers_t& meta, string
if(S3fsCurl::is_use_rrs){ if(S3fsCurl::is_use_rrs){
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-storage-class:REDUCED_REDUNDANCY"); requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-storage-class:REDUCED_REDUNDANCY");
} }
if(ow_sse_flg && S3fsCurl::is_use_sse){ if(S3fsCurl::is_use_sse){
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption:AES256"); requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption:AES256");
}else if(S3fsCurl::IsSseCustomMode()){
string md5;
if(!AddSseKeyRequestHead(md5, false)){
DPRNNN("Failed to insert sse(-c) header.");
}
} }
if(is_use_ahbe){ if(is_use_ahbe){
// set additional header by ahbe conf // set additional header by ahbe conf
@ -2584,12 +2867,12 @@ int S3fsCurl::CopyMultipartPostRequest(const char* from, const char* to, int par
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){ for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
string key = (*iter).first; string key = (*iter).first;
string value = (*iter).second; string value = (*iter).second;
if(key == "Content-Type"){ if(0 == strcasecmp(key.c_str(), "Content-Type")){
ContentType = value; ContentType = value;
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(key == "x-amz-copy-source"){ }else if(0 == strcasecmp(key.c_str(), "x-amz-copy-source")){
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
}else if(key == "x-amz-copy-source-range"){ }else if(0 == strcasecmp(key.c_str(), "x-amz-copy-source-range")){
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str()); requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
} }
// NOTICE: x-amz-acl, x-amz-server-side-encryption is not set! // NOTICE: x-amz-acl, x-amz-server-side-encryption is not set!
@ -2632,7 +2915,7 @@ int S3fsCurl::CopyMultipartPostRequest(const char* from, const char* to, int par
return result; return result;
} }
int S3fsCurl::MultipartHeadRequest(const char* tpath, off_t size, headers_t& meta) int S3fsCurl::MultipartHeadRequest(const char* tpath, off_t size, headers_t& meta, bool is_copy)
{ {
int result; int result;
string upload_id; string upload_id;
@ -2643,7 +2926,7 @@ int S3fsCurl::MultipartHeadRequest(const char* tpath, off_t size, headers_t& met
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath)); FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
if(0 != (result = PreMultipartPostRequest(tpath, meta, upload_id, false))){ if(0 != (result = PreMultipartPostRequest(tpath, meta, upload_id, is_copy))){
return result; return result;
} }
DestroyCurlHandle(); DestroyCurlHandle();
@ -2669,7 +2952,7 @@ int S3fsCurl::MultipartHeadRequest(const char* tpath, off_t size, headers_t& met
return 0; return 0;
} }
int S3fsCurl::MultipartUploadRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse_flg) int S3fsCurl::MultipartUploadRequest(const char* tpath, headers_t& meta, int fd, bool is_copy)
{ {
int result; int result;
string upload_id; string upload_id;
@ -2695,7 +2978,7 @@ int S3fsCurl::MultipartUploadRequest(const char* tpath, headers_t& meta, int fd,
return -errno; return -errno;
} }
if(0 != (result = PreMultipartPostRequest(tpath, meta, upload_id, ow_sse_flg))){ if(0 != (result = PreMultipartPostRequest(tpath, meta, upload_id, is_copy))){
close(fd2); close(fd2);
return result; return result;
} }
@ -2748,7 +3031,7 @@ int S3fsCurl::MultipartRenameRequest(const char* from, const char* to, headers_t
meta["Content-Type"] = S3fsCurl::LookupMimeType(string(to)); meta["Content-Type"] = S3fsCurl::LookupMimeType(string(to));
meta["x-amz-copy-source"] = srcresource; meta["x-amz-copy-source"] = srcresource;
if(0 != (result = PreMultipartPostRequest(to, meta, upload_id, false))){ if(0 != (result = PreMultipartPostRequest(to, meta, upload_id, true))){
return result; return result;
} }
DestroyCurlHandle(); DestroyCurlHandle();

View File

@ -100,6 +100,8 @@ class S3fsMultiCurl;
// class S3fsCurl // class S3fsCurl
//---------------------------------------------- //----------------------------------------------
typedef std::map<std::string, std::string> iamcredmap_t; typedef std::map<std::string, std::string> iamcredmap_t;
typedef std::map<std::string, std::string> sseckeymap_t;
typedef std::list<sseckeymap_t> sseckeylist_t;
// share // share
#define SHARE_MUTEX_DNS 0 #define SHARE_MUTEX_DNS 0
@ -144,6 +146,7 @@ class S3fsCurl
static bool is_public_bucket; static bool is_public_bucket;
static std::string default_acl; // TODO: to enum static std::string default_acl; // TODO: to enum
static bool is_use_rrs; static bool is_use_rrs;
static sseckeylist_t sseckeys;
static bool is_use_sse; static bool is_use_sse;
static bool is_content_md5; static bool is_content_md5;
static bool is_verbose; static bool is_verbose;
@ -182,6 +185,8 @@ class S3fsCurl
int b_postdata_remaining; // backup for retrying int b_postdata_remaining; // backup for retrying
off_t b_partdata_startpos; // backup for retrying off_t b_partdata_startpos; // backup for retrying
ssize_t b_partdata_size; // backup for retrying ssize_t b_partdata_size; // backup for retrying
bool b_ssekey_pos; // backup for retrying
std::string b_ssekey_md5; // backup for retrying
public: public:
// constructor/destructor // constructor/destructor
@ -214,6 +219,7 @@ class S3fsCurl
static bool ParseIAMCredentialResponse(const char* response, iamcredmap_t& keyval); static bool ParseIAMCredentialResponse(const char* response, iamcredmap_t& keyval);
static bool SetIAMCredentials(const char* response); static bool SetIAMCredentials(const char* response);
static bool PushbackSseKeys(std::string& onekey);
// methods // methods
bool ResetHandle(void); bool ResetHandle(void);
@ -223,7 +229,7 @@ class S3fsCurl
bool GetUploadId(std::string& upload_id); bool GetUploadId(std::string& upload_id);
int GetIAMCredentials(void); int GetIAMCredentials(void);
int PreMultipartPostRequest(const char* tpath, headers_t& meta, std::string& upload_id, bool ow_sse_flg); int PreMultipartPostRequest(const char* tpath, headers_t& meta, std::string& upload_id, bool is_copy);
int CompleteMultipartPostRequest(const char* tpath, std::string& upload_id, etaglist_t& parts); int CompleteMultipartPostRequest(const char* tpath, std::string& upload_id, etaglist_t& parts);
int UploadMultipartPostSetup(const char* tpath, int part_num, std::string& upload_id); int UploadMultipartPostSetup(const char* tpath, int part_num, std::string& upload_id);
int UploadMultipartPostRequest(const char* tpath, int part_num, std::string& upload_id); int UploadMultipartPostRequest(const char* tpath, int part_num, std::string& upload_id);
@ -233,7 +239,7 @@ class S3fsCurl
// class methods // class methods
static bool InitS3fsCurl(const char* MimeFile = NULL); static bool InitS3fsCurl(const char* MimeFile = NULL);
static bool DestroyS3fsCurl(void); static bool DestroyS3fsCurl(void);
static int ParallelMultipartUploadRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse_flg); static int ParallelMultipartUploadRequest(const char* tpath, headers_t& meta, int fd);
static int ParallelGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size); static int ParallelGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size);
static bool CheckIAMCredentialUpdate(void); static bool CheckIAMCredentialUpdate(void);
@ -250,6 +256,12 @@ class S3fsCurl
static std::string SetDefaultAcl(const char* acl); static std::string SetDefaultAcl(const char* acl);
static bool SetUseRrs(bool flag); static bool SetUseRrs(bool flag);
static bool GetUseRrs(void) { return S3fsCurl::is_use_rrs; } static bool GetUseRrs(void) { return S3fsCurl::is_use_rrs; }
static bool SetSseKeys(const char* filepath);
static bool LoadEnvSseKeys(void);
static bool GetSseKey(std::string& md5, std::string& ssekey);
static bool GetSseKeyMd5(int pos, std::string& md5);
static int GetSseKeyCount(void);
static bool IsSseCustomMode(void);
static bool SetUseSse(bool flag); static bool SetUseSse(bool flag);
static bool GetUseSse(void) { return S3fsCurl::is_use_sse; } static bool GetUseSse(void) { return S3fsCurl::is_use_sse; }
static bool SetContentMd5(bool flag); static bool SetContentMd5(bool flag);
@ -272,24 +284,25 @@ class S3fsCurl
bool CreateCurlHandle(bool force = false); bool CreateCurlHandle(bool force = false);
bool DestroyCurlHandle(void); bool DestroyCurlHandle(void);
bool AddSseKeyRequestHead(std::string& md5, bool is_copy);
bool GetResponseCode(long& responseCode); bool GetResponseCode(long& responseCode);
int RequestPerform(void); int RequestPerform(void);
int DeleteRequest(const char* tpath); int DeleteRequest(const char* tpath);
bool PreHeadRequest(const char* tpath, const char* bpath = NULL, const char* savedpath = NULL); bool PreHeadRequest(const char* tpath, const char* bpath = NULL, const char* savedpath = NULL, int ssekey_pos = -1);
bool PreHeadRequest(std::string& tpath, std::string& bpath, std::string& savedpath) { bool PreHeadRequest(std::string& tpath, std::string& bpath, std::string& savedpath, int ssekey_pos = -1) {
return PreHeadRequest(tpath.c_str(), bpath.c_str(), savedpath.c_str()); return PreHeadRequest(tpath.c_str(), bpath.c_str(), savedpath.c_str(), ssekey_pos);
} }
int HeadRequest(const char* tpath, headers_t& meta); int HeadRequest(const char* tpath, headers_t& meta);
int PutHeadRequest(const char* tpath, headers_t& meta, bool ow_sse_flg); int PutHeadRequest(const char* tpath, headers_t& meta, bool is_copy);
int PutRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse_flg); int PutRequest(const char* tpath, headers_t& meta, int fd);
int PreGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size); int PreGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size, std::string& ssekeymd5);
int GetObjectRequest(const char* tpath, int fd, off_t start = -1, ssize_t size = -1); int GetObjectRequest(const char* tpath, int fd, off_t start = -1, ssize_t size = -1);
int CheckBucket(void); int CheckBucket(void);
int ListBucketRequest(const char* tpath, const char* query); int ListBucketRequest(const char* tpath, const char* query);
int MultipartListRequest(std::string& body); int MultipartListRequest(std::string& body);
int AbortMultipartUpload(const char* tpath, std::string& upload_id); int AbortMultipartUpload(const char* tpath, std::string& upload_id);
int MultipartHeadRequest(const char* tpath, off_t size, headers_t& meta); int MultipartHeadRequest(const char* tpath, off_t size, headers_t& meta, bool is_copy);
int MultipartUploadRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse_flg); int MultipartUploadRequest(const char* tpath, headers_t& meta, int fd, bool is_copy);
int MultipartRenameRequest(const char* from, const char* to, headers_t& meta, off_t size); int MultipartRenameRequest(const char* from, const char* to, headers_t& meta, off_t size);
// methods(valiables) // methods(valiables)
@ -309,6 +322,7 @@ class S3fsCurl
int GetMultipartRetryCount(void) const { return retry_count; } int GetMultipartRetryCount(void) const { return retry_count; }
void SetMultipartRetryCount(int retrycnt) { retry_count = retrycnt; } void SetMultipartRetryCount(int retrycnt) { retry_count = retrycnt; }
bool IsOverMultipartRetryCount(void) const { return (retry_count >= S3fsCurl::retries); } bool IsOverMultipartRetryCount(void) const { return (retry_count >= S3fsCurl::retries); }
int GetLastPreHeadSeecKeyPos(void) const { return b_ssekey_pos; }
}; };
//---------------------------------------------- //----------------------------------------------

View File

@ -855,7 +855,7 @@ bool FdEntity::LoadFull(off_t* size, bool force_load)
return true; return true;
} }
int FdEntity::RowFlush(const char* tpath, headers_t& meta, bool ow_sse_flg, bool force_sync) int FdEntity::RowFlush(const char* tpath, headers_t& meta, bool force_sync)
{ {
int result; int result;
@ -902,13 +902,13 @@ int FdEntity::RowFlush(const char* tpath, headers_t& meta, bool ow_sse_flg, bool
if(120 > S3fsCurl::GetReadwriteTimeout()){ if(120 > S3fsCurl::GetReadwriteTimeout()){
backup = S3fsCurl::SetReadwriteTimeout(120); backup = S3fsCurl::SetReadwriteTimeout(120);
} }
result = S3fsCurl::ParallelMultipartUploadRequest(tpath ? tpath : path.c_str(), meta, fd, ow_sse_flg); result = S3fsCurl::ParallelMultipartUploadRequest(tpath ? tpath : path.c_str(), meta, fd);
if(0 != backup){ if(0 != backup){
S3fsCurl::SetReadwriteTimeout(backup); S3fsCurl::SetReadwriteTimeout(backup);
} }
}else{ }else{
S3fsCurl s3fscurl(true); S3fsCurl s3fscurl(true);
result = s3fscurl.PutRequest(tpath ? tpath : path.c_str(), meta, fd, ow_sse_flg); result = s3fscurl.PutRequest(tpath ? tpath : path.c_str(), meta, fd);
} }
// seek to head of file. // seek to head of file.

View File

@ -110,8 +110,8 @@ class FdEntity
bool SetAllDisable(void) { return SetAllStatus(false); } bool SetAllDisable(void) { return SetAllStatus(false); }
bool LoadFull(off_t* size = NULL, bool force_load = false); bool LoadFull(off_t* size = NULL, bool force_load = false);
int Load(off_t start, off_t size); int Load(off_t start, off_t size);
int RowFlush(const char* tpath, headers_t& meta, bool ow_sse_flg, bool force_sync = false); int RowFlush(const char* tpath, headers_t& meta, bool force_sync = false);
int Flush(headers_t& meta, bool ow_sse_flg, bool force_sync = false) { return RowFlush(NULL, meta, ow_sse_flg, force_sync); } int Flush(headers_t& meta, bool force_sync = false) { return RowFlush(NULL, meta, force_sync); }
ssize_t Read(char* bytes, off_t start, size_t size, bool force_load = false); ssize_t Read(char* bytes, off_t start, size_t size, bool force_load = false);
ssize_t Write(const char* bytes, off_t start, size_t size); ssize_t Write(const char* bytes, off_t start, size_t size);
}; };

View File

@ -135,7 +135,7 @@ static xmlChar* get_base_exp(xmlDocPtr doc, const char* exp);
static xmlChar* get_prefix(xmlDocPtr doc); static xmlChar* get_prefix(xmlDocPtr doc);
static xmlChar* get_next_marker(xmlDocPtr doc); static xmlChar* get_next_marker(xmlDocPtr doc);
static char* get_object_name(xmlDocPtr doc, xmlNodePtr node, const char* path); static char* get_object_name(xmlDocPtr doc, xmlNodePtr node, const char* path);
static int put_headers(const char* path, headers_t& meta, bool ow_sse_flg); static int put_headers(const char* path, headers_t& meta, bool is_copy);
static int rename_large_object(const char* from, const char* to); static int rename_large_object(const char* from, const char* to);
static int create_file_object(const char* path, mode_t mode, uid_t uid, gid_t gid); static int create_file_object(const char* path, mode_t mode, uid_t uid, gid_t gid);
static int create_directory_object(const char* path, mode_t mode, time_t time, uid_t uid, gid_t gid); static int create_directory_object(const char* path, mode_t mode, time_t time, uid_t uid, gid_t gid);
@ -610,6 +610,30 @@ static int check_parent_object_access(const char* path, int mask)
return 0; return 0;
} }
//
// This function is global, is called fom curl class(GetObject).
//
char* get_object_sseckey_md5(const char* path)
{
if(!path){
return NULL;
}
headers_t meta;
if(0 != get_object_attribute(path, NULL, &meta)){
DPRNNN("Failed to get object(%s) headers", path);
return NULL;
}
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
string key = (*iter).first;
if(0 == strcasecmp(key.c_str(), "x-amz-server-side-encryption-customer-key-md5")){
return strdup((*iter).second.c_str());
}
}
return NULL;
}
static FdEntity* get_local_fent(const char* path, bool is_load) static FdEntity* get_local_fent(const char* path, bool is_load)
{ {
struct stat stobj; struct stat stobj;
@ -644,7 +668,7 @@ static FdEntity* get_local_fent(const char* path, bool is_load)
* ow_sse_flg is for over writing sse header by use_sse option. * ow_sse_flg is for over writing sse header by use_sse option.
* @return fuse return code * @return fuse return code
*/ */
static int put_headers(const char* path, headers_t& meta, bool ow_sse_flg) static int put_headers(const char* path, headers_t& meta, bool is_copy)
{ {
int result; int result;
S3fsCurl s3fscurl(true); S3fsCurl s3fscurl(true);
@ -659,11 +683,11 @@ static int put_headers(const char* path, headers_t& meta, bool ow_sse_flg)
if(buf.st_size >= FIVE_GB){ if(buf.st_size >= FIVE_GB){
// multipart // multipart
if(0 != (result = s3fscurl.MultipartHeadRequest(path, buf.st_size, meta))){ if(0 != (result = s3fscurl.MultipartHeadRequest(path, buf.st_size, meta, is_copy))){
return result; return result;
} }
}else{ }else{
if(0 != (result = s3fscurl.PutHeadRequest(path, meta, ow_sse_flg))){ if(0 != (result = s3fscurl.PutHeadRequest(path, meta, is_copy))){
return result; return result;
} }
} }
@ -767,7 +791,7 @@ static int create_file_object(const char* path, mode_t mode, uid_t uid, gid_t gi
meta["x-amz-meta-mtime"] = str(time(NULL)); meta["x-amz-meta-mtime"] = str(time(NULL));
S3fsCurl s3fscurl(true); S3fsCurl s3fscurl(true);
return s3fscurl.PutRequest(path, meta, -1, false); // fd=-1 means for creating zero byte object. return s3fscurl.PutRequest(path, meta, -1); // fd=-1 means for creating zero byte object.
} }
static int s3fs_mknod(const char *path, mode_t mode, dev_t rdev) static int s3fs_mknod(const char *path, mode_t mode, dev_t rdev)
@ -852,7 +876,7 @@ static int create_directory_object(const char* path, mode_t mode, time_t time, u
meta["x-amz-meta-mtime"] = str(time); meta["x-amz-meta-mtime"] = str(time);
S3fsCurl s3fscurl; S3fsCurl s3fscurl;
return s3fscurl.PutRequest(tpath.c_str(), meta, -1, false); // fd=-1 means for creating zero byte object. return s3fscurl.PutRequest(tpath.c_str(), meta, -1); // fd=-1 means for creating zero byte object.
} }
static int s3fs_mkdir(const char* path, mode_t mode) static int s3fs_mkdir(const char* path, mode_t mode)
@ -1014,7 +1038,7 @@ static int s3fs_symlink(const char* from, const char* to)
return -errno; return -errno;
} }
// upload // upload
if(0 != (result = ent->Flush(headers, true, true))){ if(0 != (result = ent->Flush(headers, true))){
DPRN("could not upload tmpfile(result=%d)", result); DPRN("could not upload tmpfile(result=%d)", result);
} }
FdManager::get()->Close(ent); FdManager::get()->Close(ent);
@ -1050,7 +1074,7 @@ static int rename_object(const char* from, const char* to)
meta["Content-Type"] = S3fsCurl::LookupMimeType(string(to)); meta["Content-Type"] = S3fsCurl::LookupMimeType(string(to));
meta["x-amz-metadata-directive"] = "REPLACE"; meta["x-amz-metadata-directive"] = "REPLACE";
if(0 != (result = put_headers(to, meta, false))){ if(0 != (result = put_headers(to, meta, true))){
return result; return result;
} }
result = s3fs_unlink(from); result = s3fs_unlink(from);
@ -1091,7 +1115,7 @@ static int rename_object_nocopy(const char* from, const char* to)
} }
// upload // upload
if(0 != (result = ent->RowFlush(to, meta, false, true))){ if(0 != (result = ent->RowFlush(to, meta, true))){
DPRN("could not upload file(%s): result=%d", to, result); DPRN("could not upload file(%s): result=%d", to, result);
FdManager::get()->Close(ent); FdManager::get()->Close(ent);
return result; return result;
@ -1391,7 +1415,7 @@ static int s3fs_chmod(const char* path, mode_t mode)
meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str())); meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str()));
meta["x-amz-metadata-directive"] = "REPLACE"; meta["x-amz-metadata-directive"] = "REPLACE";
if(put_headers(strpath.c_str(), meta, false) != 0){ if(put_headers(strpath.c_str(), meta, true) != 0){
return -EIO; return -EIO;
} }
StatCache::getStatCacheData()->DelStat(nowcache); StatCache::getStatCacheData()->DelStat(nowcache);
@ -1467,7 +1491,7 @@ static int s3fs_chmod_nocopy(const char* path, mode_t mode)
} }
// upload // upload
if(0 != (result = ent->Flush(meta, false, true))){ if(0 != (result = ent->Flush(meta, true))){
DPRN("could not upload file(%s): result=%d", strpath.c_str(), result); DPRN("could not upload file(%s): result=%d", strpath.c_str(), result);
FdManager::get()->Close(ent); FdManager::get()->Close(ent);
return result; return result;
@ -1553,7 +1577,7 @@ static int s3fs_chown(const char* path, uid_t uid, gid_t gid)
meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str())); meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str()));
meta["x-amz-metadata-directive"] = "REPLACE"; meta["x-amz-metadata-directive"] = "REPLACE";
if(put_headers(strpath.c_str(), meta, false) != 0){ if(put_headers(strpath.c_str(), meta, true) != 0){
return -EIO; return -EIO;
} }
StatCache::getStatCacheData()->DelStat(nowcache); StatCache::getStatCacheData()->DelStat(nowcache);
@ -1639,7 +1663,7 @@ static int s3fs_chown_nocopy(const char* path, uid_t uid, gid_t gid)
} }
// upload // upload
if(0 != (result = ent->Flush(meta, false, true))){ if(0 != (result = ent->Flush(meta, true))){
DPRN("could not upload file(%s): result=%d", strpath.c_str(), result); DPRN("could not upload file(%s): result=%d", strpath.c_str(), result);
FdManager::get()->Close(ent); FdManager::get()->Close(ent);
return result; return result;
@ -1711,7 +1735,7 @@ static int s3fs_utimens(const char* path, const struct timespec ts[2])
meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str())); meta["x-amz-copy-source"] = urlEncode(service_path + bucket + get_realpath(strpath.c_str()));
meta["x-amz-metadata-directive"] = "REPLACE"; meta["x-amz-metadata-directive"] = "REPLACE";
if(put_headers(strpath.c_str(), meta, false) != 0){ if(put_headers(strpath.c_str(), meta, true) != 0){
return -EIO; return -EIO;
} }
StatCache::getStatCacheData()->DelStat(nowcache); StatCache::getStatCacheData()->DelStat(nowcache);
@ -1796,7 +1820,7 @@ static int s3fs_utimens_nocopy(const char* path, const struct timespec ts[2])
} }
// upload // upload
if(0 != (result = ent->Flush(meta, false, true))){ if(0 != (result = ent->Flush(meta, true))){
DPRN("could not upload file(%s): result=%d", strpath.c_str(), result); DPRN("could not upload file(%s): result=%d", strpath.c_str(), result);
FdManager::get()->Close(ent); FdManager::get()->Close(ent);
return result; return result;
@ -1847,7 +1871,7 @@ static int s3fs_truncate(const char* path, off_t size)
} }
// upload // upload
if(0 != (result = ent->Flush(meta, false, true))){ if(0 != (result = ent->Flush(meta, true))){
DPRN("could not upload file(%s): result=%d", path, result); DPRN("could not upload file(%s): result=%d", path, result);
FdManager::get()->Close(ent); FdManager::get()->Close(ent);
return result; return result;
@ -2002,7 +2026,7 @@ static int s3fs_flush(const char* path, struct fuse_file_info* fi)
meta["x-amz-meta-mtime"] = str(ent_mtime); meta["x-amz-meta-mtime"] = str(ent_mtime);
} }
} }
result = ent->Flush(meta, true, false); result = ent->Flush(meta, false);
FdManager::get()->Close(ent); FdManager::get()->Close(ent);
} }
S3FS_MALLOCTRIM(0); S3FS_MALLOCTRIM(0);
@ -2078,22 +2102,36 @@ static S3fsCurl* multi_head_retry_callback(S3fsCurl* s3fscurl)
if(!s3fscurl){ if(!s3fscurl){
return NULL; return NULL;
} }
int ssec_key_pos = s3fscurl->GetLastPreHeadSeecKeyPos();
int next_retry_count = s3fscurl->GetMultipartRetryCount() + 1;
if(s3fscurl->IsOverMultipartRetryCount()){ if(s3fscurl->IsOverMultipartRetryCount()){
if(S3fsCurl::IsSseCustomMode()){
// If sse-c mode, start check not sse-c(ssec_key_pos = -1).
// do increment ssec_key_pos for checking all sse-c key.
next_retry_count = 0;
ssec_key_pos++;
if(S3fsCurl::GetSseKeyCount() <= ssec_key_pos){
DPRN("Over retry count(%d) limit(%s).", s3fscurl->GetMultipartRetryCount(), s3fscurl->GetSpacialSavedPath().c_str()); DPRN("Over retry count(%d) limit(%s).", s3fscurl->GetMultipartRetryCount(), s3fscurl->GetSpacialSavedPath().c_str());
return NULL; return NULL;
} }
}else{
DPRN("Over retry count(%d) limit(%s).", s3fscurl->GetMultipartRetryCount(), s3fscurl->GetSpacialSavedPath().c_str());
return NULL;
}
}
S3fsCurl* newcurl = new S3fsCurl(s3fscurl->IsUseAhbe()); S3fsCurl* newcurl = new S3fsCurl(s3fscurl->IsUseAhbe());
string path = s3fscurl->GetPath(); string path = s3fscurl->GetPath();
string base_path = s3fscurl->GetBasePath(); string base_path = s3fscurl->GetBasePath();
string saved_path = s3fscurl->GetSpacialSavedPath(); string saved_path = s3fscurl->GetSpacialSavedPath();
if(!newcurl->PreHeadRequest(path, base_path, saved_path)){ if(!newcurl->PreHeadRequest(path, base_path, saved_path, ssec_key_pos)){
DPRN("Could not duplicate curl object(%s).", saved_path.c_str()); DPRN("Could not duplicate curl object(%s).", saved_path.c_str());
delete newcurl; delete newcurl;
return NULL; return NULL;
} }
newcurl->SetMultipartRetryCount(s3fscurl->GetMultipartRetryCount() + 1); newcurl->SetMultipartRetryCount(next_retry_count);
return newcurl; return newcurl;
} }
@ -2135,6 +2173,8 @@ static int readdir_multi_head(const char* path, S3ObjList& head, void* buf, fuse
continue; continue;
} }
// First check for directory, start checking "not sse-c".
// If checking failed, retry to check with "sse-c" by retry callback func when sse-c mode.
S3fsCurl* s3fscurl = new S3fsCurl(); S3fsCurl* s3fscurl = new S3fsCurl();
if(!s3fscurl->PreHeadRequest(disppath, (*iter), disppath)){ // target path = cache key path.(ex "dir/") if(!s3fscurl->PreHeadRequest(disppath, (*iter), disppath)){ // target path = cache key path.(ex "dir/")
DPRNNN("Could not make curl object for head request(%s).", disppath.c_str()); DPRNNN("Could not make curl object for head request(%s).", disppath.c_str());
@ -3522,23 +3562,45 @@ static int my_fuse_opt_proc(void* data, const char* arg, int key, struct fuse_ar
return 0; return 0;
} }
if(0 == strcmp(arg, "use_sse") || 0 == STR2NCMP(arg, "use_sse=")){ if(0 == strcmp(arg, "use_sse") || 0 == STR2NCMP(arg, "use_sse=")){
off_t sse = 1;
// for an old format.
if(0 == STR2NCMP(arg, "use_sse=")){ if(0 == STR2NCMP(arg, "use_sse=")){
sse = s3fs_strtoofft(strchr(arg, '=') + sizeof(char));
}
if(0 == sse){
S3fsCurl::SetUseSse(false);
}else if(1 == sse){
if(S3fsCurl::GetUseRrs()){ if(S3fsCurl::GetUseRrs()){
fprintf(stderr, "%s: use_sse option could not be specified with use_rrs.\n", program_name.c_str()); fprintf(stderr, "%s: use_sse option could not be specified with use_rrs.\n", program_name.c_str());
return -1; return -1;
} }
const char* ssecfile = &arg[strlen("use_sse=")];
if(0 == strcmp(ssecfile, "1")){
if(S3fsCurl::IsSseCustomMode()){
fprintf (stderr, "%s: already set SSE-C key by environment, and confrict use_sse option.\n", program_name.c_str());
return -1;
}
S3fsCurl::SetUseSse(true); S3fsCurl::SetUseSse(true);
}else{ }else{
fprintf(stderr, "%s: poorly formed argument to option: use_sse\n", program_name.c_str()); // testing sse-c, try to load AES256 keys
struct stat st;
if(0 != stat(ssecfile, &st)){
fprintf (stderr, "%s: could not open use_sse keys file(%s)\n", program_name.c_str(), ssecfile);
return -1; return -1;
} }
if(st.st_mode & (S_IXUSR | S_IRWXG | S_IRWXO)){
fprintf (stderr, "%s: use_sse keys file %s should be 0600 permissions\n", program_name.c_str(), ssecfile);
return -1;
}
if(!S3fsCurl::SetSseKeys(ssecfile)){
fprintf (stderr, "%s: failed to load use_sse keys file %s\n", program_name.c_str(), ssecfile);
return -1;
}
}
}else{
if(S3fsCurl::GetUseRrs()){
fprintf(stderr, "%s: use_sse option could not be specified with use_rrs.\n", program_name.c_str());
return -1;
}
if(S3fsCurl::IsSseCustomMode()){
fprintf (stderr, "%s: already set SSE-C key by environment, and confrict use_sse option.\n", program_name.c_str());
return -1;
}
S3fsCurl::SetUseSse(true);
}
return 0; return 0;
} }
if(0 == STR2NCMP(arg, "ssl_verify_hostname=")){ if(0 == STR2NCMP(arg, "ssl_verify_hostname=")){
@ -3790,6 +3852,9 @@ int main(int argc, char* argv[])
} }
} }
// Load SSE-C Key from env
S3fsCurl::LoadEnvSseKeys();
// clear this structure // clear this structure
memset(&s3fs_oper, 0, sizeof(s3fs_oper)); memset(&s3fs_oper, 0, sizeof(s3fs_oper));

View File

@ -65,4 +65,6 @@
#endif // HAVE_MALLOC_TRIM #endif // HAVE_MALLOC_TRIM
char* get_object_sseckey_md5(const char* path);
#endif // S3FS_S3_H_ #endif // S3FS_S3_H_

View File

@ -875,7 +875,24 @@ void show_help (void)
" - this option makes Amazon's Reduced Redundancy Storage enable.\n" " - this option makes Amazon's Reduced Redundancy Storage enable.\n"
"\n" "\n"
" use_sse (default is disable)\n" " use_sse (default is disable)\n"
" - this option makes Amazon's Server Site Encryption enable.\n" " - use Amazon<6F>fs Server-Site Encryption or Server-Side Encryption\n"
" with Customer-Provided Encryption Keys.\n"
" this option can not be specified with use_rrs. specifying only \n"
" \"use_sse\" or \"use_sse=1\" enables Server-Side Encryption.\n"
" (use_sse=1 for old version)\n"
" specifying this option with file path which has some SSE-C\n"
" secret key enables Server-Side Encryption with Customer-Provided\n"
" Encryption Keys.(use_sse=file)\n"
" the file must be 600 permission. the file can have some lines,\n"
" each line is one SSE-C key. the first line in file is used as\n"
" Customer-Provided Encryption Keys for uploading and changing\n"
" headers etc.\n"
" if there are some keys after first line, those are used\n"
" downloading object which are encripted by not first key.\n"
" so that, you can keep all SSE-C keys in file, that is SSE-C\n"
" key history.\n"
" if AWSSSECKEYS environment is set, you can set SSE-C key instead\n"
" of this option.\n"
"\n" "\n"
" public_bucket (default=\"\" which means disabled)\n" " public_bucket (default=\"\" which means disabled)\n"
" - anonymously mount a public bucket when set to 1\n" " - anonymously mount a public bucket when set to 1\n"