00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00034
00035
00036
00037
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
00051
00052
00053
00054
00055
00056 ConfigPage::
00057 ~ConfigPage() {
00058 clear();
00059 }
00060
00061
00062
00063
00064
00065
00066
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
00078
00079
00080
00081
00082
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
00094
00095
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
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122 bool ConfigPage::
00123 read_prc(istream &in) {
00124
00125
00126 clear();
00127
00128
00129
00130 static const size_t buffer_size = 1024;
00131 char buffer[buffer_size];
00132
00133 #ifdef HAVE_OPENSSL
00134
00135
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
00152 char *newline = (char *)memchr((void *)buffer, '\n', count);
00153 if (newline == (char *)NULL) {
00154
00155 prev_line += string(buffer, count);
00156
00157 } else {
00158
00159 size_t length = newline - buffer;
00160 read_prc_line(prev_line + string(buffer, length + 1));
00161
00162
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
00173
00174 length = buffer_end - start;
00175 prev_line = string(start, length);
00176 }
00177
00178 if (in.fail() || in.eof()) {
00179
00180
00181
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
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
00230
00231
00232
00233
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
00247
00248
00249
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
00259
00260
00261
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
00277
00278
00279
00280
00281
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
00300
00301
00302
00303 int ConfigPage::
00304 get_num_declarations() const {
00305 return _declarations.size();
00306 }
00307
00308
00309
00310
00311
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
00321
00322
00323
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
00333
00334
00335
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
00345
00346
00347
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
00357
00358
00359
00360 void ConfigPage::
00361 output(ostream &out) const {
00362 out << "ConfigPage " << get_name() << ", " << get_num_declarations()
00363 << " declarations.";
00364 }
00365
00366
00367
00368
00369
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
00395
00396
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
00408
00409
00410
00411
00412
00413 void ConfigPage::
00414 read_prc_line(const string &line) {
00415 if (line.substr(0, 7) == "##!sig ") {
00416
00417
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
00427
00428 EVP_VerifyUpdate((EVP_MD_CTX *)_md_ctx, line.data(), line.size());
00429 #endif // HAVE_OPENSSL
00430
00431
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
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
00454 p = line.find(" #", value_begin);
00455 if (p == string::npos) {
00456
00457 p = line.length();
00458 }
00459
00460
00461
00462
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
00476
00477
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 }