/*************************************************
* Library Identification Source File             *
* (C) 1999-2003 The Botan Project                *
*************************************************/

#if defined(__QNX__)
   #define _QNX_SOURCE
#endif

#include <botan/lib_hash.h>
#include <botan/lookup.h>
#include <fstream>
#include <dlfcn.h>
#include <stdlib.h>

namespace Botan {

namespace FIPS140 {

namespace {

/*************************************************
* Hash Configuration                             *
*************************************************/
const std::string HASH_USED = "SHA-1";

/*************************************************
* Find the name of the shared object in use      *
*************************************************/
std::string lib_name()
   {
   Dl_info info;
   if(!dladdr((void*)&lib_name, &info))
      throw Self_Test_Failure("FIPS 140: Cannot find name of shared library");

   if(info.dli_fname[0] == '/')
      return std::string(info.dli_fname);

   char lib_path[PATH_MAX + 1];
   if(!realpath(info.dli_fname, lib_path))
      throw Self_Test_Failure("FIPS 140: shared object path is not absolute");

   if(lib_path[0] == '/')
      return std::string(lib_path);

   throw Self_Test_Failure("FIPS 140: shared object path is not absolute");
   }

/*************************************************
* Return the supposed hash for this libray       *
*************************************************/
std::string lib_hash(const std::string& lib_name)
   {
   std::ifstream config("/etc/checksums");

   const u32bit HASH_SIZE = output_length_of(HASH_USED);

   while(!config.eof() && !config.fail())
      {
      std::string line;
      std::getline(config, line);

      if(line.size() != lib_name.size() + 2 + 2*HASH_SIZE)
         continue;
      if(line[2*HASH_SIZE] != ' ' || line[2*HASH_SIZE+1] != ' ')
         continue;

      if(lib_name == line.substr(2*HASH_SIZE + 2, std::string::npos))
         return line.substr(0, 2*HASH_SIZE);
      }
   return "";
   }

}

/*************************************************
* Check the library checksum                     *
*************************************************/
bool lib_hash_ok(const std::string& lib_name, const std::string& hash)
   {
   Pipe pipe1(new Hash_Filter(HASH_USED), new Hex_Encoder);
   Pipe pipe2(new Hex_Decoder, new Hex_Encoder);

   DataSource_Stream in(lib_name);
   pipe1.process_msg(in);
   pipe2.process_msg(hash);

   return (pipe1.read_all_as_string() == pipe2.read_all_as_string());
   }

/*************************************************
* Check the library checksum                     *
*************************************************/
bool lib_hash_ok()
   {
   const std::string lib_path = lib_name();
   return lib_hash_ok(lib_path, lib_hash(lib_path));
   }

}

}
