OLD | NEW |
1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/nss_util.h" | 5 #include "base/nss_util.h" |
6 #include "base/nss_util_internal.h" | 6 #include "base/nss_util_internal.h" |
7 | 7 |
8 #include <nss.h> | 8 #include <nss.h> |
9 #include <plarena.h> | 9 #include <plarena.h> |
10 #include <prerror.h> | 10 #include <prerror.h> |
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
197 return PK11_ReferenceSlot(real_db_slot_); | 197 return PK11_ReferenceSlot(real_db_slot_); |
198 return PK11_GetInternalKeySlot(); | 198 return PK11_GetInternalKeySlot(); |
199 } | 199 } |
200 | 200 |
201 #if defined(USE_NSS) | 201 #if defined(USE_NSS) |
202 Lock* write_lock() { | 202 Lock* write_lock() { |
203 return &write_lock_; | 203 return &write_lock_; |
204 } | 204 } |
205 #endif // defined(USE_NSS) | 205 #endif // defined(USE_NSS) |
206 | 206 |
| 207 // This method is used to force NSS to ne initialized without a DB. |
| 208 // Call this method before NSSInitSingleton() is constructed. |
| 209 static void ForceNoDBInit() { |
| 210 force_nodb_init_ = true; |
| 211 } |
| 212 |
207 private: | 213 private: |
208 friend struct DefaultLazyInstanceTraits<NSSInitSingleton>; | 214 friend struct DefaultLazyInstanceTraits<NSSInitSingleton>; |
209 | 215 |
210 NSSInitSingleton() | 216 NSSInitSingleton() |
211 : real_db_slot_(NULL), | 217 : real_db_slot_(NULL), |
212 test_db_slot_(NULL), | 218 test_db_slot_(NULL), |
213 root_(NULL), | 219 root_(NULL), |
214 chromeos_user_logged_in_(false) { | 220 chromeos_user_logged_in_(false) { |
215 EnsureNSPRInit(); | 221 EnsureNSPRInit(); |
216 | 222 |
(...skipping 12 matching lines...) Expand all Loading... |
229 LOG(ERROR) << "NSS_VersionCheck(\"3.12.3\") failed. " | 235 LOG(ERROR) << "NSS_VersionCheck(\"3.12.3\") failed. " |
230 "We depend on NSS >= 3.12.3, and this error is not fatal " | 236 "We depend on NSS >= 3.12.3, and this error is not fatal " |
231 "only because many people have busted NSS setups (for " | 237 "only because many people have busted NSS setups (for " |
232 "example, using the wrong version of NSPR). " | 238 "example, using the wrong version of NSPR). " |
233 "Please upgrade to the latest NSS and NSPR, and if you " | 239 "Please upgrade to the latest NSS and NSPR, and if you " |
234 "still get this error, contact your distribution " | 240 "still get this error, contact your distribution " |
235 "maintainer."; | 241 "maintainer."; |
236 } | 242 } |
237 | 243 |
238 SECStatus status = SECFailure; | 244 SECStatus status = SECFailure; |
| 245 bool nodb_init = force_nodb_init_; |
| 246 |
239 #if !defined(USE_NSS) | 247 #if !defined(USE_NSS) |
240 // Use the system certificate store, so initialize NSS without database. | 248 // Use the system certificate store, so initialize NSS without database. |
241 status = NSS_NoDB_Init(NULL); | 249 nodb_init = true; |
242 if (status != SECSuccess) { | 250 #endif |
243 LOG(ERROR) << "Error initializing NSS without a persistent " | |
244 "database: NSS error code " << PR_GetError(); | |
245 } | |
246 #else | |
247 FilePath database_dir = GetInitialConfigDirectory(); | |
248 if (!database_dir.empty()) { | |
249 // This duplicates the work which should have been done in | |
250 // EarlySetupForNSSInit. However, this function is idempotent so there's | |
251 // no harm done. | |
252 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); | |
253 | 251 |
254 // Initialize with a persistent database (likely, ~/.pki/nssdb). | 252 if (nodb_init) { |
255 // Use "sql:" which can be shared by multiple processes safely. | |
256 std::string nss_config_dir = | |
257 StringPrintf("sql:%s", database_dir.value().c_str()); | |
258 #if defined(OS_CHROMEOS) | |
259 status = NSS_Init(nss_config_dir.c_str()); | |
260 #else | |
261 status = NSS_InitReadWrite(nss_config_dir.c_str()); | |
262 #endif | |
263 if (status != SECSuccess) { | |
264 LOG(ERROR) << "Error initializing NSS with a persistent " | |
265 "database (" << nss_config_dir | |
266 << "): NSS error code " << PR_GetError(); | |
267 } | |
268 } | |
269 if (status != SECSuccess) { | |
270 LOG(WARNING) << "Initialize NSS without a persistent database " | |
271 "(~/.pki/nssdb)."; | |
272 status = NSS_NoDB_Init(NULL); | 253 status = NSS_NoDB_Init(NULL); |
273 if (status != SECSuccess) { | 254 if (status != SECSuccess) { |
274 LOG(ERROR) << "Error initializing NSS without a persistent " | 255 LOG(ERROR) << "Error initializing NSS without a persistent " |
275 "database: NSS error code " << PR_GetError(); | 256 "database: NSS error code " << PR_GetError(); |
276 return; | |
277 } | 257 } |
| 258 } else { |
| 259 FilePath database_dir = GetInitialConfigDirectory(); |
| 260 if (!database_dir.empty()) { |
| 261 // This duplicates the work which should have been done in |
| 262 // EarlySetupForNSSInit. However, this function is idempotent so |
| 263 // there's no harm done. |
| 264 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); |
| 265 |
| 266 // Initialize with a persistent database (likely, ~/.pki/nssdb). |
| 267 // Use "sql:" which can be shared by multiple processes safely. |
| 268 std::string nss_config_dir = |
| 269 StringPrintf("sql:%s", database_dir.value().c_str()); |
| 270 #if defined(OS_CHROMEOS) |
| 271 status = NSS_Init(nss_config_dir.c_str()); |
| 272 #else |
| 273 status = NSS_InitReadWrite(nss_config_dir.c_str()); |
| 274 #endif |
| 275 if (status != SECSuccess) { |
| 276 LOG(ERROR) << "Error initializing NSS with a persistent " |
| 277 "database (" << nss_config_dir |
| 278 << "): NSS error code " << PR_GetError(); |
| 279 } |
| 280 } |
| 281 if (status != SECSuccess) { |
| 282 LOG(WARNING) << "Initialize NSS without a persistent database " |
| 283 "(~/.pki/nssdb)."; |
| 284 status = NSS_NoDB_Init(NULL); |
| 285 if (status != SECSuccess) { |
| 286 LOG(ERROR) << "Error initializing NSS without a persistent " |
| 287 "database: NSS error code " << PR_GetError(); |
| 288 return; |
| 289 } |
| 290 } |
| 291 |
| 292 PK11_SetPasswordFunc(PKCS11PasswordFunc); |
| 293 |
| 294 // If we haven't initialized the password for the NSS databases, |
| 295 // initialize an empty-string password so that we don't need to |
| 296 // log in. |
| 297 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); |
| 298 if (slot) { |
| 299 // PK11_InitPin may write to the keyDB, but no other thread can use NSS |
| 300 // yet, so we don't need to lock. |
| 301 if (PK11_NeedUserInit(slot)) |
| 302 PK11_InitPin(slot, NULL, NULL); |
| 303 PK11_FreeSlot(slot); |
| 304 } |
| 305 |
| 306 root_ = InitDefaultRootCerts(); |
278 } | 307 } |
279 | |
280 PK11_SetPasswordFunc(PKCS11PasswordFunc); | |
281 | |
282 // If we haven't initialized the password for the NSS databases, | |
283 // initialize an empty-string password so that we don't need to | |
284 // log in. | |
285 PK11SlotInfo* slot = PK11_GetInternalKeySlot(); | |
286 if (slot) { | |
287 // PK11_InitPin may write to the keyDB, but no other thread can use NSS | |
288 // yet, so we don't need to lock. | |
289 if (PK11_NeedUserInit(slot)) | |
290 PK11_InitPin(slot, NULL, NULL); | |
291 PK11_FreeSlot(slot); | |
292 } | |
293 | |
294 root_ = InitDefaultRootCerts(); | |
295 #endif // !defined(USE_NSS) | |
296 } | 308 } |
297 | 309 |
298 // NOTE(willchan): We don't actually execute this code since we leak NSS to | 310 // NOTE(willchan): We don't actually execute this code since we leak NSS to |
299 // prevent non-joinable threads from using NSS after it's already been shut | 311 // prevent non-joinable threads from using NSS after it's already been shut |
300 // down. | 312 // down. |
301 ~NSSInitSingleton() { | 313 ~NSSInitSingleton() { |
302 if (real_db_slot_) { | 314 if (real_db_slot_) { |
303 SECMOD_CloseUserDB(real_db_slot_); | 315 SECMOD_CloseUserDB(real_db_slot_); |
304 PK11_FreeSlot(real_db_slot_); | 316 PK11_FreeSlot(real_db_slot_); |
305 real_db_slot_ = NULL; | 317 real_db_slot_ = NULL; |
(...skipping 24 matching lines...) Expand all Loading... |
330 if (PK11_NeedUserInit(db_slot)) | 342 if (PK11_NeedUserInit(db_slot)) |
331 PK11_InitPin(db_slot, NULL, NULL); | 343 PK11_InitPin(db_slot, NULL, NULL); |
332 } | 344 } |
333 else { | 345 else { |
334 LOG(ERROR) << "Error opening persistent database (" << modspec | 346 LOG(ERROR) << "Error opening persistent database (" << modspec |
335 << "): NSS error code " << PR_GetError(); | 347 << "): NSS error code " << PR_GetError(); |
336 } | 348 } |
337 return db_slot; | 349 return db_slot; |
338 } | 350 } |
339 | 351 |
| 352 // If this is set to true NSS is forced to be initialized without a DB. |
| 353 static bool force_nodb_init_; |
| 354 |
340 PK11SlotInfo* real_db_slot_; // Overrides internal key slot if non-NULL. | 355 PK11SlotInfo* real_db_slot_; // Overrides internal key slot if non-NULL. |
341 PK11SlotInfo* test_db_slot_; // Overrides internal key slot and real_db_slot_ | 356 PK11SlotInfo* test_db_slot_; // Overrides internal key slot and real_db_slot_ |
342 SECMODModule *root_; | 357 SECMODModule *root_; |
343 bool chromeos_user_logged_in_; | 358 bool chromeos_user_logged_in_; |
344 #if defined(USE_NSS) | 359 #if defined(USE_NSS) |
345 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 | 360 // TODO(davidben): When https://bugzilla.mozilla.org/show_bug.cgi?id=564011 |
346 // is fixed, we will no longer need the lock. | 361 // is fixed, we will no longer need the lock. |
347 Lock write_lock_; | 362 Lock write_lock_; |
348 #endif // defined(USE_NSS) | 363 #endif // defined(USE_NSS) |
349 }; | 364 }; |
350 | 365 |
| 366 bool NSSInitSingleton::force_nodb_init_ = false; |
| 367 |
351 LazyInstance<NSSInitSingleton, LeakyLazyInstanceTraits<NSSInitSingleton> > | 368 LazyInstance<NSSInitSingleton, LeakyLazyInstanceTraits<NSSInitSingleton> > |
352 g_nss_singleton(LINKER_INITIALIZED); | 369 g_nss_singleton(LINKER_INITIALIZED); |
353 | 370 |
354 } // namespace | 371 } // namespace |
355 | 372 |
356 #if defined(USE_NSS) | 373 #if defined(USE_NSS) |
357 void EarlySetupForNSSInit() { | 374 void EarlySetupForNSSInit() { |
358 FilePath database_dir = GetInitialConfigDirectory(); | 375 FilePath database_dir = GetInitialConfigDirectory(); |
359 if (!database_dir.empty()) | 376 if (!database_dir.empty()) |
360 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); | 377 UseLocalCacheOfNSSDatabaseIfNFS(database_dir); |
361 } | 378 } |
362 #endif | 379 #endif |
363 | 380 |
364 void EnsureNSPRInit() { | 381 void EnsureNSPRInit() { |
365 g_nspr_singleton.Get(); | 382 g_nspr_singleton.Get(); |
366 } | 383 } |
367 | 384 |
368 void EnsureNSSInit() { | 385 void EnsureNSSInit() { |
369 // Initializing SSL causes us to do blocking IO. | 386 // Initializing SSL causes us to do blocking IO. |
370 // Temporarily allow it until we fix | 387 // Temporarily allow it until we fix |
371 // http://code.google.com/p/chromium/issues/detail?id=59847 | 388 // http://code.google.com/p/chromium/issues/detail?id=59847 |
372 ThreadRestrictions::ScopedAllowIO allow_io; | 389 ThreadRestrictions::ScopedAllowIO allow_io; |
373 g_nss_singleton.Get(); | 390 g_nss_singleton.Get(); |
374 } | 391 } |
375 | 392 |
| 393 void EnsureNSSNoDBInit() { |
| 394 ThreadRestrictions::ScopedAllowIO allow_io; |
| 395 |
| 396 // Force NSS to be initialized without a DB. |
| 397 NSSInitSingleton::ForceNoDBInit(); |
| 398 g_nss_singleton.Get(); |
| 399 } |
| 400 |
| 401 void DisableNSSForkCheck() { |
| 402 scoped_ptr<Environment> env(Environment::Create()); |
| 403 env->SetVar("NSS_STRICT_NOFORK", "DISABLED"); |
| 404 } |
| 405 |
376 bool CheckNSSVersion(const char* version) { | 406 bool CheckNSSVersion(const char* version) { |
377 return !!NSS_VersionCheck(version); | 407 return !!NSS_VersionCheck(version); |
378 } | 408 } |
379 | 409 |
380 #if defined(USE_NSS) | 410 #if defined(USE_NSS) |
381 bool OpenTestNSSDB(const FilePath& path, const char* description) { | 411 bool OpenTestNSSDB(const FilePath& path, const char* description) { |
382 return g_nss_singleton.Get().OpenTestNSSDB(path, description); | 412 return g_nss_singleton.Get().OpenTestNSSDB(path, description); |
383 } | 413 } |
384 | 414 |
385 void CloseTestNSSDB() { | 415 void CloseTestNSSDB() { |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
427 exploded.millisecond = prxtime.tm_usec / 1000; | 457 exploded.millisecond = prxtime.tm_usec / 1000; |
428 | 458 |
429 return Time::FromUTCExploded(exploded); | 459 return Time::FromUTCExploded(exploded); |
430 } | 460 } |
431 | 461 |
432 PK11SlotInfo* GetDefaultNSSKeySlot() { | 462 PK11SlotInfo* GetDefaultNSSKeySlot() { |
433 return g_nss_singleton.Get().GetDefaultKeySlot(); | 463 return g_nss_singleton.Get().GetDefaultKeySlot(); |
434 } | 464 } |
435 | 465 |
436 } // namespace base | 466 } // namespace base |
OLD | NEW |