// make a random 32-char string // (the MD5 of some quasi-random bits) // int make_random_string(char* out) { char buf[256]; #ifdef _WIN32 HCRYPTPROV hCryptProv; if(! CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) { return -1; } if(! CryptGenRandom(hCryptProv, (DWORD) 32, (BYTE *) buf)) { CryptReleaseContext(hCryptProv, 0); return -1; } CryptReleaseContext(hCryptProv, 0); #elif defined ANDROID // /dev/random not available on Android, using stdlib function instead int i = rand(); snprintf(buf, sizeof(buf), "%d", i); #else #ifndef _USING_FCGI_ FILE* f = fopen("/dev/random", "r"); #else FILE* f = FCGI::fopen("/dev/random", "r"); #endif if (!f) { return -1; } size_t n = fread(buf, 32, 1, f); fclose(f); if (n != 1) return -1; #endif md5_block((const unsigned char*)buf, 32, out); return 0; }
// update the DB record to the values in "xhost" // "initial_host" stores the current DB values; // update only those fields that have changed // static int update_host_record(HOST& initial_host, HOST& xhost, USER& user) { DB_HOST host; int retval; char buf[1024]; host = xhost; // hash the CPID reported by the host with the user's email address. // This prevents one user from spoofing another one's host. // if (strlen(host.host_cpid)) { sprintf(buf, "%s%s", host.host_cpid, user.email_addr); md5_block((const unsigned char*)buf, strlen(buf), host.host_cpid); } char* p = getenv("REMOTE_ADDR"); if (p) { strlcpy(host.external_ip_addr, p, sizeof(host.external_ip_addr)); } retval = host.update_diff_sched(initial_host); if (retval) { log_messages.printf(MSG_CRITICAL, "host.update() failed: %s\n", boincerror(retval) ); } return 0; }
int make_random_string(char* out) { char buf[256]; #ifdef _WIN32 HCRYPTPROV hCryptProv; if(! CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) { return -1; } if(! CryptGenRandom(hCryptProv, (DWORD) 32, (BYTE *) buf)) { CryptReleaseContext(hCryptProv, 0); return -1; } CryptReleaseContext(hCryptProv, 0); #else FILE* f = fopen("/dev/random", "r"); if (!f) { return -1; } size_t n = fread(buf, 32, 1, f); fclose(f); if (n != 1) return -1; #endif md5_block((const unsigned char*)buf, 32, out); return 0; }
void MD5_Update(MD5_CTX *c, register unsigned char *data, MD5_LONG len) { register ULONG *p; int sw,sc; ULONG l; if (len == 0) return; l=(c->Nl+(len<<3))&0xffffffffL; /* 95-05-24 eay Fixed a bug with the overflow handling, thanks to * Wei Dai <*****@*****.**> for pointing it out. */ if (l < c->Nl) /* overflow */ c->Nh++; c->Nh+=(len>>29); c->Nl=l; if (c->num != 0) { p=c->data; sw=c->num>>2; sc=c->num&0x03; if ((c->num+len) >= MD5_CBLOCK) { l= p[sw]; p_c2l(data,l,sc); p[sw++]=l; for (; sw<MD5_LBLOCK; sw++) { c2l(data,l); p[sw]=l; } len-=(MD5_CBLOCK-c->num); md5_block(c,p); c->num=0; /* drop through and do the rest */ } else { int ew,ec; c->num+=(int)len; if ((sc+len) < 4) { /* ugly, add char's to a word */ l= p[sw]; p_c2l_p(data,l,sc,len); p[sw]=l; } else { ew=(c->num>>2); ec=(c->num&0x03); l= p[sw]; p_c2l(data,l,sc); p[sw++]=l; for (; sw < ew; sw++) { c2l(data,l); p[sw]=l; } if (ec) { c2l_p(data,l,ec); p[sw]=l; } } return; } }
// find the user's most recently-created host with given host CPID // static bool find_host_by_cpid(DB_USER& user, char* host_cpid, DB_HOST& host) { char buf[1024], buf2[256]; sprintf(buf, "%s%s", host_cpid, user.email_addr); md5_block((const unsigned char*)buf, strlen(buf), buf2); sprintf(buf, "where userid=%d and host_cpid='%s' order by id desc", user.id, buf2 ); if (!host.enumerate(buf)) { host.end_enumerate(); return true; } return false; }
int sign_block(DATA_BLOCK& data_block, R_RSA_PRIVATE_KEY& key, DATA_BLOCK& signature) { char md5_buf[MD5_LEN]; int retval; DATA_BLOCK in_block; md5_block(data_block.data, data_block.len, md5_buf); in_block.data = (unsigned char*)md5_buf; in_block.len = (unsigned int)strlen(md5_buf); retval = encrypt_private(key, in_block, signature); if (retval) { printf("sign_block: encrypt_private returned %d\n", retval); return retval; } return 0; }
// make a host cross-project ID. // Should be unique across hosts with very high probability // void HOST_INFO::generate_host_cpid() { // Assume that get_mac_addresses can be ported to any unix system. // If not, it can return false. // #if defined(__linux__) || defined(_WIN32) || defined(__APPLE__ ) || defined(__unix) char buffer[8192] = ""; // must be big enough to accommodate aa:bb:cc:dd:ee:ff // times the number of network interfaces, // plus the domain name, IP addr, and OS name. // 8K should suffice if (!get_mac_addresses(buffer) || ! strcmp(buffer, "")) { make_random_string("", host_cpid); return; } strcat(buffer, domain_name); strcat(buffer, ip_addr); strcat(buffer, os_name); md5_block((unsigned char*)buffer, (int)strlen(buffer), host_cpid); #else make_random_string("", host_cpid); #endif }
// same, both text and signature are char strings // int check_string_signature( const char* text, const char* signature_text, R_RSA_PUBLIC_KEY& key, bool& answer ) { char md5_buf[MD5_LEN]; unsigned char signature_buf[SIGNATURE_SIZE_BINARY]; char clear_buf[MD5_LEN]; int retval, n; DATA_BLOCK signature, clear_signature; retval = md5_block((const unsigned char*)text, (int)strlen(text), md5_buf); if (retval) return retval; n = (int)strlen(md5_buf); signature.data = signature_buf; signature.len = sizeof(signature_buf); retval = sscan_hex_data(signature_text, signature); if (retval) return retval; clear_signature.data = (unsigned char*)clear_buf; clear_signature.len = 256; retval = decrypt_public(key, signature, clear_signature); if (retval) return retval; answer = !strncmp(md5_buf, clear_buf, n); return 0; }
// make a random string using host info. // Not recommended for password generation; // use as a last resort if more secure methods fail // void HOST_INFO::make_random_string(const char* salt, char* out) { char buf[1024]; sprintf(buf, "%f%s%s%f%s", dtime(), domain_name, ip_addr, d_free, salt); md5_block((const unsigned char*) buf, (int)strlen(buf), out); }
void MD5_Update(MD5_CTX *c, register unsigned char *data, unsigned long len) { register ULONG *p; int sw,sc; ULONG l; if (len == 0) return; l=(c->Nl+(len<<3))&0xffffffffL; if (l < c->Nl) /* overflow */ c->Nh++; c->Nh+=(len>>29); c->Nl=l; if (c->num != 0) { p=c->data; sw=c->num>>2; sc=c->num&0x03; if ((c->num+len) >= MD5_CBLOCK) { l= p[sw]; p_c2l(data,l,sc); p[sw++]=l; for (; sw<MD5_LBLOCK; sw++) { c2l(data,l); p[sw]=l; } len-=(MD5_CBLOCK-c->num); md5_block(c,p); c->num=0; /* drop through and do the rest */ } else { int ew,ec; c->num+=(int)len; if ((sc+len) < 4) /* ugly, add char's to a word */ { l= p[sw]; p_c2l_p(data,l,sc,len); p[sw]=l; } else { ew=(c->num>>2); ec=(c->num&0x03); l= p[sw]; p_c2l(data,l,sc); p[sw++]=l; for (; sw < ew; sw++) { c2l(data,l); p[sw]=l; } if (ec) { c2l_p(data,l,ec); p[sw]=l; } } return; } }
void get_rss_auth(USER& user, char* buf) { char buf2[256], out[256]; sprintf(buf2, "%s%s%s", user.authenticator, user.passwd_hash, "notify_rss"); md5_block((unsigned char*)buf2, strlen(buf2), out); sprintf(buf, "%d_%s", user.id, out); }
// Based on the info in the request message, // look up the host and its user, and make sure the authenticator matches. // Some special cases: // 1) If no host ID is supplied, or if RPC seqno mismatch, // create a new host record // 2) If the host record specified by g_request->hostid is a "zombie" // (i.e. it was merged with another host via the web site) // then follow links to find the proper host // // POSTCONDITION: // If this function returns zero, then: // - reply.host contains a valid host record (possibly new) // - reply.user contains a valid user record // - if user belongs to a team, reply.team contains team record // int authenticate_user() { int retval; char buf[1024]; DB_HOST host; DB_USER user; DB_TEAM team; if (g_request->hostid) { retval = host.lookup_id(g_request->hostid); while (!retval && host.userid==0) { // if host record is zombie, follow link to new host // retval = host.lookup_id(host.rpc_seqno); if (!retval) { g_reply->hostid = host.id; log_messages.printf(MSG_NORMAL, "[HOST#%d] forwarding to new host ID %d\n", g_request->hostid, host.id ); } } if (retval) { g_reply->insert_message("Can't find host record", "low"); log_messages.printf(MSG_NORMAL, "[HOST#%d?] can't find host\n", g_request->hostid ); g_request->hostid = 0; goto lookup_user_and_make_new_host; } g_reply->host = host; // look up user based on the ID in host record, // and see if the authenticator matches (regular or weak) // g_request->using_weak_auth = false; sprintf(buf, "where id=%d", host.userid); retval = user.lookup(buf); if (!retval && !strcmp(user.authenticator, g_request->authenticator)) { // req auth matches user auth - go on } else { if (!retval) { // user for host.userid exists - check weak auth // get_weak_auth(user, buf); if (!strcmp(buf, g_request->authenticator)) { g_request->using_weak_auth = true; log_messages.printf(MSG_DEBUG, "[HOST#%d] accepting weak authenticator\n", host.id ); } } if (!g_request->using_weak_auth) { // weak auth failed - look up user based on authenticator // strlcpy( user.authenticator, g_request->authenticator, sizeof(user.authenticator) ); escape_string(user.authenticator, sizeof(user.authenticator)); sprintf(buf, "where authenticator='%s'", user.authenticator); retval = user.lookup(buf); if (retval) { g_reply->insert_message( _("Invalid or missing account key. To fix, remove and add this project."), "notice" ); g_reply->set_delay(DELAY_MISSING_KEY); g_reply->nucleus_only = true; log_messages.printf(MSG_CRITICAL, "[HOST#%d] [USER#%d] Bad authenticator '%s'\n", host.id, user.id, g_request->authenticator ); return ERR_AUTHENTICATOR; } } } g_reply->user = user; if (host.userid != user.id) { // If the request's host ID isn't consistent with the authenticator, // create a new host record. // log_messages.printf(MSG_NORMAL, "[HOST#%d] [USER#%d] inconsistent host ID; creating new host\n", host.id, user.id ); goto make_new_host; } // If the seqno from the host is less than what we expect, // the user must have copied the state file to a different host. // Make a new host record. // if (!batch && g_request->rpc_seqno < g_reply->host.rpc_seqno) { g_request->hostid = 0; log_messages.printf(MSG_NORMAL, "[HOST#%d] [USER#%d] RPC seqno %d less than expected %d; creating new host\n", g_reply->host.id, user.id, g_request->rpc_seqno, g_reply->host.rpc_seqno ); goto make_new_host; } } else { // Here no hostid was given, or the ID was bad. // Look up the user, then create a new host record // lookup_user_and_make_new_host: // if authenticator contains _, it's a weak auth // if (strchr(g_request->authenticator, '_')) { int userid = atoi(g_request->authenticator); retval = user.lookup_id(userid); if (!retval) { get_weak_auth(user, buf); if (strcmp(buf, g_request->authenticator)) { retval = ERR_AUTHENTICATOR; } } } else { strlcpy( user.authenticator, g_request->authenticator, sizeof(user.authenticator) ); escape_string(user.authenticator, sizeof(user.authenticator)); sprintf(buf, "where authenticator='%s'", user.authenticator); retval = user.lookup(buf); } if (retval) { g_reply->insert_message( "Invalid or missing account key. To fix, remove and add this project .", "low" ); g_reply->set_delay(DELAY_MISSING_KEY); log_messages.printf(MSG_CRITICAL, "[HOST#<none>] Bad authenticator '%s': %s\n", g_request->authenticator, boincerror(retval) ); return ERR_AUTHENTICATOR; } g_reply->user = user; // If host CPID is present, // scan backwards through this user's hosts, // looking for one with the same host CPID. // If we find one, it means the user detached and reattached. // Use the existing host record, // and mark in-progress results as over. // if (strlen(g_request->host.host_cpid)) { if (find_host_by_cpid(user, g_request->host.host_cpid, host)) { log_messages.printf(MSG_NORMAL, "[HOST#%d] [USER#%d] No host ID in request, but host with matching CPID found.\n", host.id, host.userid ); if ((g_request->allow_multiple_clients != 1) && (g_request->other_results.size() == 0) ) { mark_results_over(host); } goto got_host; } } make_new_host: // One final attempt to locate an existing host record: // scan backwards through this user's hosts, // looking for one with the same host name, // IP address, processor and amount of RAM. // If found, use the existing host record, // and mark in-progress results as over. // // NOTE: If the client was run with --allow_multiple_clients, skip this. // if ((g_request->allow_multiple_clients != 1) && find_host_by_other(user, g_request->host, host) ) { log_messages.printf(MSG_NORMAL, "[HOST#%d] [USER#%d] Found similar existing host for this user - assigned.\n", host.id, host.userid ); mark_results_over(host); goto got_host; } // either of the above cases, // or host ID didn't match user ID, // or RPC seqno was too low. // // Create a new host. // g_reply->user is filled in and valid at this point // host = g_request->host; host.id = 0; host.create_time = time(0); host.userid = g_reply->user.id; host.rpc_seqno = 0; host.expavg_time = time(0); safe_strcpy(host.venue, g_reply->user.venue); host.fix_nans(); retval = host.insert(); if (retval) { g_reply->insert_message( "Couldn't create host record in database", "low" ); boinc_db.print_error("host.insert()"); log_messages.printf(MSG_CRITICAL, "host.insert() failed\n"); return retval; } host.id = boinc_db.insert_id(); got_host: g_reply->host = host; g_reply->hostid = g_reply->host.id; // this tells client to updates its host ID g_request->rpc_seqno = 0; // this value eventually gets written to host DB record; // for new hosts it must be zero. // This kludge forces this. } // have user record in g_reply->user at this point // if (g_reply->user.teamid) { retval = team.lookup_id(g_reply->user.teamid); if (!retval) g_reply->team = team; } // compute email hash // md5_block( (unsigned char*)g_reply->user.email_addr, strlen(g_reply->user.email_addr), g_reply->email_hash ); // if new user CPID, update user record // if (!g_request->using_weak_auth && strlen(g_request->cross_project_id)) { if (strcmp(g_request->cross_project_id, g_reply->user.cross_project_id)) { user.id = g_reply->user.id; escape_string(g_request->cross_project_id, sizeof(g_request->cross_project_id)); sprintf(buf, "cross_project_id='%s'", g_request->cross_project_id); unescape_string(g_request->cross_project_id, sizeof(g_request->cross_project_id)); user.update_field(buf); } } return 0; }
std::string md5_string(const unsigned char* data, int nbytes) { char output[MD5_LEN]; md5_block(data, nbytes, output); return std::string(output); }