0
0
mirror of https://github.com/mongodb/mongo.git synced 2024-12-01 09:32:32 +01:00

clean up nonce implementation

This commit is contained in:
dwight 2011-06-05 18:13:18 -04:00
parent 69186d293c
commit 4d5715086f
7 changed files with 57 additions and 51 deletions

View File

@ -34,7 +34,7 @@ namespace mongo {
#elif defined(__linux__) || defined(__APPLE__) || defined(__sunos__)
pid = (unsigned short) getpid();
#else
pid = (unsigned short) security.getNonce();
pid = (unsigned short) Security::getNonce();
#endif
return pid;
}
@ -53,13 +53,13 @@ namespace mongo {
// this is not called often, so the following is not expensive, and gives us some
// testing that nonce generation is working right and that our OIDs are (perhaps) ok.
{
nonce a = security.getNonce();
nonce b = security.getNonce();
nonce c = security.getNonce();
nonce64 a = Security::getNonceDuringInit();
nonce64 b = Security::getNonceDuringInit();
nonce64 c = Security::getNonceDuringInit();
assert( !(a==b && b==c) );
}
unsigned long long n = security.getNonce();
unsigned long long n = Security::getNonceDuringInit();
OID::MachineAndPid x = ourMachine = (OID::MachineAndPid&) n;
foldInPid(x);
return x;
@ -96,7 +96,7 @@ namespace mongo {
}
void OID::init() {
static AtomicUInt inc = (unsigned) security.getNonce();
static AtomicUInt inc = (unsigned) Security::getNonce();
{
unsigned t = (unsigned) time(0);

View File

@ -41,6 +41,8 @@ namespace mongo {
class AlignedBuilder;
unsigned goodRandomNumberSlow();
namespace dur {
// Rotate after reaching this data size in a journal (j._<n>) file
// We use a smaller size for 32 bit as the journal is mmapped during recovery (only)
@ -118,15 +120,13 @@ namespace mongo {
strncpy(dbpath, fname.c_str(), sizeof(dbpath)-1);
{
fileId = t&0xffffffff;
fileId |= ((unsigned long long)getRandomNumber()) << 32;
fileId |= ((unsigned long long)goodRandomNumberSlow()) << 32;
}
memset(reserved3, 0, sizeof(reserved3));
txt2[0] = txt2[1] = '\n';
n1 = n2 = n3 = n4 = '\n';
}
// class Journal
Journal j;
const unsigned long long LsnShutdownSentinel = ~((unsigned long long)0);

View File

@ -23,7 +23,9 @@ extern int do_md5_test(void);
namespace mongo {
BOOST_STATIC_ASSERT( sizeof(nonce) == 8 );
BOOST_STATIC_ASSERT( sizeof(nonce64) == 8 );
static Security security; // needs to be static so _initialized is preset to false (see initsafe below)
Security::Security() {
static int n;
@ -31,7 +33,7 @@ namespace mongo {
init();
}
void Security::init() {
NOINLINE_DECL void Security::init() {
if( _initialized ) return;
_initialized = true;
@ -39,7 +41,7 @@ namespace mongo {
_devrandom = new ifstream("/dev/urandom", ios::binary|ios::in);
massert( 10353 , "can't open dev/urandom", _devrandom->is_open() );
#elif defined(_WIN32)
srand(curTimeMicros());
srand(curTimeMicros()); // perhaps not relevant for rand_s but we might want elsewhere anyway
#else
srandomdev();
#endif
@ -50,21 +52,12 @@ namespace mongo {
#endif
}
nonce Security::getNonce() {
static mongo::mutex m("getNonce");
scoped_lock lk(m);
if ( ! _initialized )
init();
/* question/todo: /dev/random works on OS X. is it better
to use that than random() / srandom()?
*/
nonce n;
nonce64 Security::__getNonce() {
dassert( _initialized );
nonce64 n;
#if defined(__linux__) || defined(__sunos__) || defined(__APPLE__)
_devrandom->read((char*)&n, sizeof(n));
massert( 10355 , "devrandom failed", !_devrandom->fail());
massert(10355 , "devrandom failed", !_devrandom->fail());
#elif defined(_WIN32)
unsigned a=0, b=0;
assert( rand_s(&a) == 0 );
@ -75,9 +68,28 @@ namespace mongo {
#endif
return n;
}
unsigned getRandomNumber() { return (unsigned) security.getNonce(); }
bool Security::_initialized;
Security security;
SimpleMutex nonceMutex("nonce");
nonce64 Security::_getNonce() {
// not good this is a static as gcc will mutex protect it which costs time
SimpleMutex::scoped_lock lk(nonceMutex);
if( !_initialized )
init();
return __getNonce();
}
nonce64 Security::getNonceDuringInit() {
// the mutex might not be inited yet. init phase should be one thread anyway (hopefully we don't spawn threads therein)
if( !security._initialized )
security.init();
return security.__getNonce();
}
nonce64 Security::getNonce() {
return security._getNonce();
}
// name warns us this might be a little slow (see code above)
unsigned goodRandomNumberSlow() { return (unsigned) Security::getNonce(); }
} // namespace mongo

View File

@ -1,4 +1,4 @@
// nonce.h
// @file nonce.h
/* Copyright 2009 10gen Inc.
*
@ -19,24 +19,18 @@
namespace mongo {
typedef unsigned long long nonce;
typedef unsigned long long nonce64;
struct Security {
Security();
nonce getNonce();
/** safe during global var initialization */
nonce getNonceInitSafe() {
init();
return getNonce();
}
static nonce64 getNonce();
static nonce64 getNonceDuringInit(); // use this version during global var constructors
private:
nonce64 _getNonce();
nonce64 __getNonce();
ifstream *_devrandom;
static bool _initialized;
bool _initialized;
void init(); // can call more than once
};
extern Security security;
} // namespace mongo

View File

@ -39,12 +39,12 @@ namespace mongo {
getnonce sends nonce to client
client then sends { authenticate:1, nonce:<nonce_str>, user:<username>, key:<key> }
client then sends { authenticate:1, nonce64:<nonce_str>, user:<username>, key:<key> }
where <key> is md5(<nonce_str><username><pwd_digest_str>) as a string
*/
boost::thread_specific_ptr<nonce> lastNonce;
boost::thread_specific_ptr<nonce64> lastNonce;
class CmdGetNonce : public Command {
public:
@ -57,7 +57,7 @@ namespace mongo {
virtual LockType locktype() const { return NONE; }
CmdGetNonce() : Command("getnonce") {}
bool run(const string&, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl) {
nonce *n = new nonce(security.getNonce());
nonce64 *n = new nonce64(Security::getNonce());
stringstream ss;
ss << hex << *n;
result.append("nonce", ss.str() );
@ -116,7 +116,7 @@ namespace mongo {
{
bool reject = false;
nonce *ln = lastNonce.release();
nonce64 *ln = lastNonce.release();
if ( ln == 0 ) {
reject = true;
log(1) << "auth: no lastNonce" << endl;

View File

@ -184,7 +184,7 @@ namespace mongo {
long long CursorCache::genId() {
while ( true ) {
long long x = security.getNonce();
long long x = Security::getNonce();
if ( x == 0 )
continue;
if ( x < 0 )

View File

@ -1744,8 +1744,8 @@ const StringData _jscode_raw_db =
"this.getCollection( \"system.users\" ).remove( { user : username } );\n"
"}\n"
"\n"
"DB.prototype.__pwHash = function( nonce, username, pass ) {\n"
"return hex_md5( nonce + username + hex_md5( username + \":mongo:\" + pass ) );\n"
"DB.prototype.__pwHash = function( nonce64, username, pass ) {\n"
"return hex_md5( nonce64 + username + hex_md5( username + \":mongo:\" + pass ) );\n"
"}\n"
"\n"
"DB.prototype.auth = function( username , pass ){\n"
@ -1755,8 +1755,8 @@ const StringData _jscode_raw_db =
"{\n"
"authenticate : 1 ,\n"
"user : username ,\n"
"nonce : n.nonce ,\n"
"key : this.__pwHash( n.nonce, username, pass )\n"
"nonce64 : n.nonce64 ,\n"
"key : this.__pwHash( n.nonce64, username, pass )\n"
"}\n"
");\n"
"\n"
@ -1925,7 +1925,7 @@ const StringData _jscode_raw_db =
"fromhost = fromhost || \"\";\n"
"if ( username && password ) {\n"
"var n = this._adminCommand( { copydbgetnonce : 1, fromhost:fromhost } );\n"
"return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb, username:username, nonce:n.nonce, key:this.__pwHash( n.nonce, username, password ) } );\n"
"return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb, username:username, nonce64:n.nonce64, key:this.__pwHash( n.nonce64, username, password ) } );\n"
"} else {\n"
"return this._adminCommand( { copydb:1, fromhost:fromhost, fromdb:fromdb, todb:todb } );\n"
"}\n"