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 _sort(implicit_load ? 10 : 0),
00045 _next_decl_seq(1),
00046 _trust_level(0)
00047 {
00048 }
00049
00050
00051
00052
00053
00054
00055
00056
00057 ConfigPage::
00058 ~ConfigPage() {
00059 clear();
00060 }
00061
00062
00063
00064
00065
00066
00067
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
00079
00080
00081
00082
00083
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
00095
00096
00097
00098
00099
00100
00101
00102
00103
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
00115
00116
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
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143 bool ConfigPage::
00144 read_prc(istream &in) {
00145
00146
00147 clear();
00148
00149
00150
00151 static const size_t buffer_size = 1024;
00152 char buffer[buffer_size];
00153
00154 #ifdef HAVE_OPENSSL
00155
00156
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
00173 char *newline = (char *)memchr((void *)buffer, '\n', count);
00174 if (newline == (char *)NULL) {
00175
00176 prev_line += string(buffer, count);
00177
00178 } else {
00179
00180 size_t length = newline - buffer;
00181 read_prc_line(prev_line + string(buffer, length + 1));
00182
00183
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
00194
00195 length = buffer_end - start;
00196 prev_line = string(start, length);
00197 }
00198
00199 if (in.fail() || in.eof()) {
00200
00201
00202
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
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
00251
00252
00253
00254
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
00268
00269
00270
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
00280
00281
00282
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
00298
00299
00300
00301
00302
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
00321
00322
00323
00324 int ConfigPage::
00325 get_num_declarations() const {
00326 return _declarations.size();
00327 }
00328
00329
00330
00331
00332
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
00342
00343
00344
00345
00346
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
00356
00357
00358
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
00368
00369
00370
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
00380
00381
00382
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
00392
00393
00394
00395 void ConfigPage::
00396 output(ostream &out) const {
00397 out << "ConfigPage " << get_name() << ", " << get_num_declarations()
00398 << " declarations.";
00399 }
00400
00401
00402
00403
00404
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
00430
00431
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
00443
00444
00445
00446
00447
00448 void ConfigPage::
00449 read_prc_line(const string &line) {
00450 if (line.substr(0, 7) == "##!sig ") {
00451
00452
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
00462
00463 EVP_VerifyUpdate((EVP_MD_CTX *)_md_ctx, line.data(), line.size());
00464 #endif // HAVE_OPENSSL
00465
00466
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
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
00489 p = line.find(" #", value_begin);
00490 if (p == string::npos) {
00491
00492 p = line.length();
00493 }
00494
00495
00496
00497
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
00511
00512
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 }