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