Panda3D

configPage.cxx

00001 // Filename: configPage.cxx
00002 // Created by:  drose (15Oct04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "configPage.h"
00016 #include "configDeclaration.h"
00017 #include "configVariableCore.h"
00018 #include "configVariableManager.h"
00019 #include "prcKeyRegistry.h"
00020 #include "config_prc.h"
00021 #include "encryptStream.h"
00022 
00023 #include <ctype.h>
00024 
00025 #ifdef HAVE_OPENSSL
00026 #include "openssl/evp.h"
00027 #endif
00028 
00029 ConfigPage *ConfigPage::_default_page = NULL;
00030 ConfigPage *ConfigPage::_local_page = NULL;
00031 
00032 ////////////////////////////////////////////////////////////////////
00033 //     Function: ConfigPage::Constructor
00034 //       Access: Private
00035 //  Description: The constructor is private because a ConfigPage
00036 //               should be constructed via the ConfigPageManager
00037 //               make_page() interface.
00038 ////////////////////////////////////////////////////////////////////
00039 ConfigPage::
00040 ConfigPage(const string &name, bool implicit_load, int page_seq) :
00041   _name(name),
00042   _implicit_load(implicit_load),
00043   _page_seq(page_seq),
00044   _next_decl_seq(1),
00045   _trust_level(0)
00046 {
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: ConfigPage::Destructor
00051 //       Access: Private
00052 //  Description: The destructor is private because a ConfigPage
00053 //               should be deleted via the ConfigPageManager
00054 //               delete_page() interface.
00055 ////////////////////////////////////////////////////////////////////
00056 ConfigPage::
00057 ~ConfigPage() {
00058   clear();
00059 }
00060 
00061 ////////////////////////////////////////////////////////////////////
00062 //     Function: ConfigPage::get_default_page
00063 //       Access: Published, Static
00064 //  Description: Returns a pointer to the global "default page".  This
00065 //               is the ConfigPage that lists all variables' original
00066 //               default values.
00067 ////////////////////////////////////////////////////////////////////
00068 ConfigPage *ConfigPage::
00069 get_default_page() {
00070   if (_default_page == (ConfigPage *)NULL) {
00071     _default_page = new ConfigPage("default", false, 0);
00072   }
00073   return _default_page;
00074 }
00075 
00076 ////////////////////////////////////////////////////////////////////
00077 //     Function: ConfigPage::get_local_page
00078 //       Access: Published, Static
00079 //  Description: Returns a pointer to the global "local page".  This
00080 //               is the ConfigPage that lists the locally-assigned
00081 //               values for any variables in the world that have such
00082 //               a local assignment.
00083 ////////////////////////////////////////////////////////////////////
00084 ConfigPage *ConfigPage::
00085 get_local_page() {
00086   if (_local_page == (ConfigPage *)NULL) {
00087     _local_page = new ConfigPage("local", false, 0);
00088   }
00089   return _local_page;
00090 }
00091 
00092 ////////////////////////////////////////////////////////////////////
00093 //     Function: ConfigPage::clear
00094 //       Access: Published
00095 //  Description: Removes all of the declarations from the page.
00096 ////////////////////////////////////////////////////////////////////
00097 void ConfigPage::
00098 clear() {
00099   Declarations::iterator di;
00100   for (di = _declarations.begin(); di != _declarations.end(); ++di) {
00101     ConfigDeclaration *decl = (*di);
00102     delete decl;
00103   }
00104   _declarations.clear();
00105   _trust_level = 0;
00106   _signature = string();
00107 }
00108 
00109 ////////////////////////////////////////////////////////////////////
00110 //     Function: ConfigPage::read_prc
00111 //       Access: Published
00112 //  Description: Reads the contents of a complete prc file, as
00113 //               returned by the indicated istream, into the current
00114 //               page file.  Returns true on success, or false on some
00115 //               I/O error.
00116 //
00117 //               This is a low-level interface.  Normally you do not
00118 //               need to call it directly.  See the global functions
00119 //               load_prc_file() and unload_prc_file(), defined in
00120 //               panda/src/putil, for a higher-level interface.
00121 ////////////////////////////////////////////////////////////////////
00122 bool ConfigPage::
00123 read_prc(istream &in) {
00124   // We must empty the page before we start to read it; otherwise
00125   // trust level is meaningless.
00126   clear();
00127 
00128   // We avoid getline() here because of its notorious problem with
00129   // last lines that lack a trailing newline character.
00130   static const size_t buffer_size = 1024;
00131   char buffer[buffer_size];
00132 
00133 #ifdef HAVE_OPENSSL
00134   // Set up the evp context for verifying the signature, if we find
00135   // one.
00136 #ifdef SSL_097
00137   _md_ctx = EVP_MD_CTX_create();
00138 #else
00139   _md_ctx = new EVP_MD_CTX;
00140 #endif
00141   EVP_VerifyInit((EVP_MD_CTX *)_md_ctx, EVP_sha1());
00142 #endif  // HAVE_OPENSSL
00143 
00144   string prev_line;
00145 
00146   in.read(buffer, buffer_size);
00147   size_t count = in.gcount();
00148   while (count != 0) {
00149     char *buffer_end = buffer + count;
00150 
00151     // Look for the first line in the buffer..
00152     char *newline = (char *)memchr((void *)buffer, '\n', count);
00153     if (newline == (char *)NULL) {
00154       // The buffer was one long line.  Huh.
00155       prev_line += string(buffer, count);
00156 
00157     } else {
00158       // Process the first line in the buffer.
00159       size_t length = newline - buffer;
00160       read_prc_line(prev_line + string(buffer, length + 1));
00161 
00162       // Now look for the next line, etc.
00163       char *start = newline + 1;
00164       newline = (char *)memchr((void *)start, '\n', buffer_end - start);
00165       while (newline != (char *)NULL) {
00166         length = newline - start;
00167         read_prc_line(string(start, length + 1));
00168         start = newline + 1;
00169         newline = (char *)memchr((void *)start, '\n', buffer_end - start);
00170       }
00171 
00172       // The remaining text in the buffer is the start of the next
00173       // line.
00174       length = buffer_end - start;
00175       prev_line = string(start, length);
00176     }
00177 
00178     if (in.fail() || in.eof()) {
00179       // If we got a failure reading the buffer last time, don't keep
00180       // reading again.  Irix seems to require this test; otherwise,
00181       // it repeatedly returns the same text at the end of the file.
00182       count = 0;
00183 
00184     } else {
00185       in.read(buffer, buffer_size);
00186       count = in.gcount();
00187     }
00188   }
00189 
00190   if (!prev_line.empty()) {
00191     read_prc_line(prev_line);
00192   }
00193 
00194 #ifdef HAVE_OPENSSL
00195   // Now validate the signature and free the SSL structures.
00196   if (!_signature.empty()) {
00197     PrcKeyRegistry *pkr = PrcKeyRegistry::get_global_ptr();
00198     int num_keys = pkr->get_num_keys();
00199     for (int i = 1; i < num_keys && _trust_level == 0; i++) {
00200       EVP_PKEY *pkey = pkr->get_key(i);
00201       if (pkey != (EVP_PKEY *)NULL) {
00202         int verify_result = 
00203           EVP_VerifyFinal((EVP_MD_CTX *)_md_ctx, 
00204                           (unsigned char *)_signature.data(), 
00205                           _signature.size(), pkey);
00206         if (verify_result == 1) {
00207           _trust_level = i;
00208         }
00209       }
00210     }
00211     if (_trust_level == 0) {
00212       prc_cat->info() 
00213         << "invalid signature found in " << get_name() << "\n";
00214     }
00215   }
00216 #ifdef SSL_097
00217   EVP_MD_CTX_destroy((EVP_MD_CTX *)_md_ctx);
00218 #else
00219   delete (EVP_MD_CTX *)_md_ctx;
00220 #endif
00221 #endif  // HAVE_OPENSSL
00222 
00223   bool failed = (in.fail() && !in.eof());
00224 
00225   return !failed;
00226 }
00227 
00228 ////////////////////////////////////////////////////////////////////
00229 //     Function: ConfigPage::read_encrypted_prc
00230 //       Access: Published
00231 //  Description: Automatically decrypts and reads the stream, given
00232 //               the indicated password.  Note that if the password is
00233 //               incorrect, the result may be garbage.
00234 ////////////////////////////////////////////////////////////////////
00235 bool ConfigPage::
00236 read_encrypted_prc(istream &in, const string &password) {
00237 #ifdef HAVE_OPENSSL
00238   IDecryptStream decrypt(&in, false, password);
00239   return read_prc(decrypt);
00240 #else
00241   return false;
00242 #endif  // HAVE_OPENSSL
00243 }
00244 
00245 ////////////////////////////////////////////////////////////////////
00246 //     Function: ConfigPage::make_declaration
00247 //       Access: Published
00248 //  Description: Adds the indicated variable/value pair as a new
00249 //               declaration on the page.
00250 ////////////////////////////////////////////////////////////////////
00251 ConfigDeclaration *ConfigPage::
00252 make_declaration(const string &variable, const string &value) {
00253   ConfigVariableManager *variable_mgr = ConfigVariableManager::get_global_ptr();
00254   return make_declaration(variable_mgr->make_variable(variable), value);
00255 }
00256 
00257 ////////////////////////////////////////////////////////////////////
00258 //     Function: ConfigPage::make_declaration
00259 //       Access: Published
00260 //  Description: Adds the indicated variable/value pair as a new
00261 //               declaration on the page.
00262 ////////////////////////////////////////////////////////////////////
00263 ConfigDeclaration *ConfigPage::
00264 make_declaration(ConfigVariableCore *variable, const string &value) {
00265   ConfigDeclaration *decl = new ConfigDeclaration
00266     (this, variable, value, _next_decl_seq);
00267   _next_decl_seq++;
00268 
00269   _declarations.push_back(decl);
00270   make_dirty();
00271 
00272   return decl;
00273 }
00274 
00275 ////////////////////////////////////////////////////////////////////
00276 //     Function: ConfigPage::delete_declaration
00277 //       Access: Published
00278 //  Description: Removes the indicated declaration from the page and
00279 //               deletes it.  Returns true if the declaration is
00280 //               successfully removed, false if it was not on the
00281 //               page.
00282 ////////////////////////////////////////////////////////////////////
00283 bool ConfigPage::
00284 delete_declaration(ConfigDeclaration *decl) {
00285   Declarations::iterator di;
00286   for (di = _declarations.begin(); di != _declarations.end(); ++di) {
00287     if ((*di) == decl) {
00288       _declarations.erase(di);
00289       delete decl;
00290       make_dirty();
00291       return true;
00292     }
00293   }
00294 
00295   return false;
00296 }
00297 
00298 ////////////////////////////////////////////////////////////////////
00299 //     Function: ConfigPage::get_num_declarations
00300 //       Access: Published
00301 //  Description: Returns the number of declarations on the page.
00302 ////////////////////////////////////////////////////////////////////
00303 int ConfigPage::
00304 get_num_declarations() const {
00305   return _declarations.size();
00306 }
00307 
00308 ////////////////////////////////////////////////////////////////////
00309 //     Function: ConfigPage::get_declaration
00310 //       Access: Published
00311 //  Description: Returns the nth declaration on the page.
00312 ////////////////////////////////////////////////////////////////////
00313 const ConfigDeclaration *ConfigPage::
00314 get_declaration(int n) const {
00315   nassertr(n >= 0 && n < (int)_declarations.size(), (ConfigDeclaration *)NULL);
00316   return _declarations[n];
00317 }
00318 
00319 ////////////////////////////////////////////////////////////////////
00320 //     Function: ConfigPage::get_variable_name
00321 //       Access: Published
00322 //  Description: Returns the variable named by the nth declaration on
00323 //               the page.
00324 ////////////////////////////////////////////////////////////////////
00325 string ConfigPage::
00326 get_variable_name(int n) const {
00327   nassertr(n >= 0 && n < (int)_declarations.size(), string());
00328   return _declarations[n]->get_variable()->get_name();
00329 }
00330 
00331 ////////////////////////////////////////////////////////////////////
00332 //     Function: ConfigPage::get_string_value
00333 //       Access: Published
00334 //  Description: Returns the value assigned by the nth declaration on
00335 //               the page.
00336 ////////////////////////////////////////////////////////////////////
00337 string ConfigPage::
00338 get_string_value(int n) const {
00339   nassertr(n >= 0 && n < (int)_declarations.size(), string());
00340   return _declarations[n]->get_string_value();
00341 }
00342 
00343 ////////////////////////////////////////////////////////////////////
00344 //     Function: ConfigPage::is_variable_used
00345 //       Access: Published
00346 //  Description: Returns true if the nth active variable on
00347 //               the page has been used by code, false otherwise.
00348 ////////////////////////////////////////////////////////////////////
00349 bool ConfigPage::
00350 is_variable_used(int n) const {
00351   nassertr(n >= 0 && n < (int)_declarations.size(), false);
00352   return _declarations[n]->get_variable()->is_used();
00353 }
00354 
00355 ////////////////////////////////////////////////////////////////////
00356 //     Function: ConfigPage::output
00357 //       Access: Published
00358 //  Description: 
00359 ////////////////////////////////////////////////////////////////////
00360 void ConfigPage::
00361 output(ostream &out) const {
00362   out << "ConfigPage " << get_name() << ", " << get_num_declarations()
00363       << " declarations.";
00364 }
00365 
00366 ////////////////////////////////////////////////////////////////////
00367 //     Function: ConfigPage::output_brief_signature
00368 //       Access: Published
00369 //  Description: Outputs the first few hex digits of the signature.
00370 ////////////////////////////////////////////////////////////////////
00371 void ConfigPage::
00372 output_brief_signature(ostream &out) const {
00373   size_t num_bytes = min(_signature.size(), (size_t)8);
00374   for (size_t p = 0; p < num_bytes; ++p) {
00375     unsigned int byte = _signature[p];
00376 
00377     unsigned int hi = (byte >> 4) & 0xf;
00378     if (hi >= 10) {
00379       out << (char)((hi - 10) + 'a');
00380     } else {
00381       out << (char)(hi + '0');
00382     }
00383 
00384     unsigned int lo = byte & 0xf;
00385     if (lo >= 10) {
00386       out << (char)((lo - 10) + 'a');
00387     } else {
00388       out << (char)(lo + '0');
00389     }
00390   }
00391 }
00392 
00393 ////////////////////////////////////////////////////////////////////
00394 //     Function: ConfigPage::write
00395 //       Access: Published
00396 //  Description: 
00397 ////////////////////////////////////////////////////////////////////
00398 void ConfigPage::
00399 write(ostream &out) const {
00400   Declarations::const_iterator di;
00401   for (di = _declarations.begin(); di != _declarations.end(); ++di) {
00402     (*di)->write(out);
00403   }
00404 }
00405 
00406 ////////////////////////////////////////////////////////////////////
00407 //     Function: ConfigPage::read_prc_line
00408 //       Access: Private
00409 //  Description: Handles reading in a single line from a .prc file.
00410 //               This is called internally by read_prc() for each
00411 //               line.
00412 ////////////////////////////////////////////////////////////////////
00413 void ConfigPage::
00414 read_prc_line(const string &line) {
00415   if (line.substr(0, 7) == "##!sig ") {
00416     // This is a signature.  Accumulate it into the signature and
00417     // return, and don't count it as contributing to the hash.
00418     for (size_t p = 7; p < line.length() - 1; p += 2) {
00419       unsigned char digit = (hex_digit(line[p]) << 4) | hex_digit(line[p + 1]);
00420       _signature += digit;
00421     }
00422     return;
00423   }
00424 
00425 #ifdef HAVE_OPENSSL
00426   // Accumulate any line that's not itself a signature into the hash,
00427   // so we can validate the signature at the end.
00428   EVP_VerifyUpdate((EVP_MD_CTX *)_md_ctx, line.data(), line.size());
00429 #endif  // HAVE_OPENSSL
00430 
00431   // Separate the line into a variable and a value.
00432   size_t p = 0;
00433   while (p < line.length() && isspace((unsigned char)line[p])) {
00434     p++;
00435   }
00436 
00437   if (p == line.length() || line[p] == '#') {
00438     // Blank line or comment; do nothing.
00439     return;
00440   }
00441 
00442   size_t variable_begin = p;
00443   while (p < line.length() && !isspace((unsigned char)line[p])) {
00444     p++;
00445   }
00446   size_t variable_end = p;
00447 
00448   while (p < line.length() && isspace((unsigned char)line[p])) {
00449     p++;
00450   }
00451   size_t value_begin = p;
00452 
00453   // Is there an embedded comment on this line?
00454   p = line.find(" #", value_begin);
00455   if (p == string::npos) {
00456     // No, the value extends all the way to the end of the line.
00457     p = line.length();
00458   }
00459 
00460   // The value extends from here to the end of the line (or to the
00461   // start of the embedded comment), so trim whitespace backwards off
00462   // from there.
00463   while (p > value_begin && isspace((unsigned char)line[p - 1])) {
00464     p--;
00465   }
00466   size_t value_end = p;
00467 
00468   string variable = line.substr(variable_begin, variable_end - variable_begin);
00469   string value = line.substr(value_begin, value_end - value_begin);
00470 
00471   make_declaration(variable, value);
00472 }
00473 
00474 ////////////////////////////////////////////////////////////////////
00475 //     Function: ConfigPage::hex_digit
00476 //       Access: Private, Static
00477 //  Description: Decodes a hex digit into its numeric value.
00478 ////////////////////////////////////////////////////////////////////
00479 unsigned int ConfigPage::
00480 hex_digit(unsigned char digit) {
00481   if (isalpha(digit)) {
00482     return tolower(digit) - 'a' + 10;
00483   } else if (isdigit(digit)) {
00484     return digit - '0';
00485   } else {
00486     return 0;
00487   }
00488 }
 All Classes Functions Variables Enumerations