// ----------------------------------------------------------------------
// File: SharedPath.cc
// Author: Andreas-Joachim Peters - CERN
// ----------------------------------------------------------------------
/************************************************************************
* EOS - the CERN Disk Storage System *
* Copyright (C) 2011 CERN/Switzerland *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see .*
************************************************************************/
// -----------------------------------------------------------------------
// This file is included source code in XrdMgmOfs.cc to make the code more
// transparent without slowing down the compilation time.
// -----------------------------------------------------------------------
/*----------------------------------------------------------------------------*/
std::string
XrdMgmOfs::CreateSharePath(const char* inpath,
const char* ininfo,
time_t expires,
XrdOucErrInfo& error,
eos::common::VirtualIdentity& vid)
/*----------------------------------------------------------------------------*/
/*
* @brief create a file sharing path with given liftime
*
* @param path file path to share
* @param info opaque information
* @param expires unixtimestamp when signature has to expire
* @param error error object
* @param vid virtual ID of the caller
*
* @return signed path ?
*/
{
NAMESPACEMAP;
errno = 0;
if (_access(path, R_OK, error, vid, "")) {
errno = EPERM;
return std::string("");
}
XrdSfsFileExistence file_exists;
if ((_exists(path, file_exists, error, vid, 0))) {
errno = ENOENT;
return std::string("");
}
if (file_exists != XrdSfsFileExistIsFile) {
errno = EISDIR;
return std::string("");
}
struct stat buf;
eos::common::VirtualIdentity rootvid = eos::common::VirtualIdentity::Root();
if (_stat(path, &buf, error, rootvid)) {
return std::string("");
}
std::string signit = path;
signit += "?";
char sexpires[256];
snprintf(sexpires, sizeof(sexpires) - 1, "%u", (unsigned int) expires);
signit += "eos.share.expires=";
signit += sexpires;
signit += "&eos.share.fxid=";
const std::string hex_fid = eos::common::FileId::Fid2Hex(buf.st_ino);
signit += hex_fid.c_str();
signit += "&eos.share.signature=";
eos::common::SymKey* symkey = eos::common::gSymKeyStore.GetCurrentKey();
if (!symkey) {
errno = ENOKEY;
return std::string("");
}
XrdOucString ouc_sign = sexpires;
ouc_sign += path;
ouc_sign += sexpires;
ouc_sign += gOFS->MgmOfsInstanceName;
ouc_sign += hex_fid.c_str();
XrdOucString ouc_signed;
if (!eos::common::SymKey::SymmetricStringEncrypt(ouc_sign, ouc_signed,
(char*) symkey->GetKey())) {
errno = EKEYREJECTED;
return std::string("");
}
while (ouc_signed.replace("\n", "")) {
}
signit += ouc_signed.c_str();
return signit;
}
/*----------------------------------------------------------------------------*/
bool
XrdMgmOfs::VerifySharePath(const char* path,
XrdOucEnv* opaque)
/*----------------------------------------------------------------------------*/
/*
* @brief verify a file sharing path
*
* @param path file path to share
* @param opaque information containing a file share signature
*
* @return true if valid otherwise false
*/
{
// check if this is a signed path
if (!opaque->Get("eos.share.signature")) {
return false;
}
// check if this has a valid expiration date
XrdOucString expires = opaque->Get("eos.share.expires");
if (!expires.length() || expires == "0") {
return false;
}
// check if this has fid
XrdOucString fxid = opaque->Get("eos.share.fxid");
if (!fxid.length()) {
return false;
}
// get the fid
struct stat buf;
eos::common::VirtualIdentity rootvid = eos::common::VirtualIdentity::Root();
XrdOucErrInfo error;
if (_stat(path, &buf, error, rootvid)) {
return false;
}
const std::string hex_fid = eos::common::FileId::Fid2Hex(buf.st_ino);
if (std::string(fxid.c_str()) != hex_fid) {
eos_warning("msg=\"shared file has changed file id - share URL not valid anymore\"");
return false;
}
// check that it is not yet expired
time_t expired = strtoul(expires.c_str(), 0, 10);
time_t now = time(NULL);
if (!expired || (expired < now)) {
int envlen;
eos_static_err("msg=\"shared link expired\" path=%s info=%s\n", path,
opaque->Env(envlen));
return false;
}
eos::common::SymKey* symkey = eos::common::gSymKeyStore.GetCurrentKey();
if (!symkey) {
eos_static_err("msg=\"failed to retrieve symmetric key to verify shared link");
return false;
}
// verify the signature
XrdOucString ouc_sign = expires;
ouc_sign += path;
ouc_sign += expires;
ouc_sign += gOFS->MgmOfsInstanceName;
ouc_sign += hex_fid.c_str();
XrdOucString ouc_signed;
if (!eos::common::SymKey::SymmetricStringEncrypt(ouc_sign, ouc_signed,
(char*) symkey->GetKey())) {
eos_static_err("msg=\"failed to encrypt to verify shared link");
return false;
}
while (ouc_signed.replace("\n", "")) {
}
XrdOucString ouc_signature = opaque->Get("eos.share.signature");
if (ouc_signature == ouc_signed) {
return true;
} else {
int envlen;
eos_static_err("msg=\"shared link with invalid signature\" path=%s info=%s len=%d len=%d\n",
path, opaque->Env(envlen), ouc_signature.length(), ouc_signed.length());
return false;
}
}