1 #include "otsdaq/WebUsersUtilities/WebUsers.h"
2 #include "otsdaq/XmlUtilities/HttpXmlDocument.h"
4 #include <openssl/sha.h>
18 #define WEB_LOGIN_BKUP_DB_PATH "bkup/"
20 #define SECURITY_FILE_NAME std::string(__ENV__("SERVICE_DATA_PATH")) + "/OtsWizardData/security.dat"
22 #define USERS_ACTIVE_SESSIONS_FILE USERS_DB_PATH + "/activeSessions.sv"
24 #define HASHES_DB_FILE HASHES_DB_PATH + "/hashes.xml"
25 #define USERS_DB_FILE USERS_DB_PATH + "/users.xml"
26 #define USERS_GLOBAL_HISTORY_FILE "__global"
27 #define USERS_LOGIN_HISTORY_FILETYPE "hist"
28 #define USERS_PREFERENCES_FILETYPE "pref"
29 #define SYSTEM_PREFERENCES_PREFIX "system.preset"
30 #define USER_WITH_LOCK_FILE WEB_LOGIN_DB_PATH + "/user_with_lock.dat"
31 #define IP_BLACKLIST_FILE WEB_LOGIN_DB_PATH + "/ip_generated_blacklist.dat"
32 #define IP_REJECT_FILE WEB_LOGIN_DB_PATH + "/ip_reject.dat"
33 #define IP_ACCEPT_FILE WEB_LOGIN_DB_PATH + "/ip_accept.dat"
35 #define SILENCE_ALL_TOOLTIPS_FILENAME "silenceTooltips"
37 #define HASHES_DB_GLOBAL_STRING "hashData"
38 #define HASHES_DB_ENTRY_STRING "hashEntry"
39 #define USERS_DB_GLOBAL_STRING "userData"
40 #define USERS_DB_ENTRY_STRING "userEntry"
41 #define USERS_DB_NEXT_UID_STRING "nextUserId"
44 #define PREF_XML_BGCOLOR_FIELD "pref_bgcolor" // -background color
45 #define PREF_XML_DBCOLOR_FIELD "pref_dbcolor" // -dashboard color
46 #define PREF_XML_WINCOLOR_FIELD "pref_wincolor" // -window color
47 #define PREF_XML_LAYOUT_FIELD "pref_layout" // -3 defaults window layouts(and current)
48 #define PREF_XML_SYSLAYOUT_FIELD "pref_syslayout" // -2 defaults window layouts
49 #define PREF_XML_PERMISSIONS_FIELD "desktop_user_permissions" // 0-255 permissions value (255 is admin super user)
50 #define PREF_XML_USERLOCK_FIELD "username_with_lock" // user with lock (to lockout others)
51 #define PREF_XML_USERNAME_FIELD "pref_username" // user with lock (to lockout others)
52 #define PREF_XML_OTS_OWNER_FIELD "ots_owner" // e.g. the experiment name
54 #define PREF_XML_BGCOLOR_DEFAULT "rgb(0,76,151)" // -background color
55 #define PREF_XML_DBCOLOR_DEFAULT "rgb(0,40,85)" // -dashboard color
56 #define PREF_XML_WINCOLOR_DEFAULT "rgba(196,229,255,0.9)" // -window color
57 #define PREF_XML_LAYOUT_DEFAULT "0;0;0;0" // 3 default window layouts(and current)
58 #define PREF_XML_SYSLAYOUT_DEFAULT "0;0" // 2 system default window layouts
60 #define PREF_XML_ACCOUNTS_FIELD "users_accounts" // user accounts field for super users
61 #define PREF_XML_LOGIN_HISTORY_FIELD "login_entry" // login history field for user login history data
63 const std::string WebUsers::OTS_OWNER = getenv(
"OTS_OWNER")?getenv(
"OTS_OWNER"):
"";
64 const std::string WebUsers::DEFAULT_ADMIN_USERNAME =
"admin";
65 const std::string WebUsers::DEFAULT_ADMIN_DISPLAY_NAME =
"Administrator";
66 const std::string WebUsers::DEFAULT_ADMIN_EMAIL =
"root@otsdaq.fnal.gov";
67 const std::string WebUsers::DEFAULT_ITERATOR_USERNAME =
"iterator";
68 const std::string WebUsers::DEFAULT_STATECHANGER_USERNAME =
"statechanger";
69 const std::string WebUsers::DEFAULT_USER_GROUP =
"allUsers";
71 const std::string WebUsers::REQ_NO_LOGIN_RESPONSE =
"NoLogin";
72 const std::string WebUsers::REQ_NO_PERMISSION_RESPONSE =
"NoPermission";
73 const std::string WebUsers::REQ_USER_LOCKOUT_RESPONSE =
"UserLockout";
74 const std::string WebUsers::REQ_LOCK_REQUIRED_RESPONSE =
"LockRequired";
75 const std::string WebUsers::REQ_ALLOW_NO_USER =
"AllowNoUser";
77 const std::string WebUsers::SECURITY_TYPE_NONE =
"NoSecurity";
78 const std::string WebUsers::SECURITY_TYPE_DIGEST_ACCESS =
"DigestAccessAuthentication";
82 #define __MF_SUBJECT__ "WebUsers"
91 usersUsernameWithLock_ =
"";
94 HashesDatabaseEntryFields.push_back(
"hash");
95 HashesDatabaseEntryFields.push_back(
98 UsersDatabaseEntryFields.push_back(
"username");
99 UsersDatabaseEntryFields.push_back(
"displayName");
100 UsersDatabaseEntryFields.push_back(
"salt");
101 UsersDatabaseEntryFields.push_back(
"uid");
102 UsersDatabaseEntryFields.push_back(
"permissions");
103 UsersDatabaseEntryFields.push_back(
"lastLoginAttemptTime");
104 UsersDatabaseEntryFields.push_back(
"accountCreatedTime");
105 UsersDatabaseEntryFields.push_back(
"loginFailureCount");
106 UsersDatabaseEntryFields.push_back(
"lastModifiedTime");
107 UsersDatabaseEntryFields.push_back(
"lastModifierUsername");
108 UsersDatabaseEntryFields.push_back(
"useremail");
111 mkdir(((std::string)WEB_LOGIN_DB_PATH).c_str(), 0755);
112 mkdir(((std::string)WEB_LOGIN_DB_PATH +
"bkup/" + USERS_DB_PATH).c_str(), 0755);
113 mkdir(((std::string)WEB_LOGIN_DB_PATH + HASHES_DB_PATH).c_str(), 0755);
114 mkdir(((std::string)WEB_LOGIN_DB_PATH + USERS_DB_PATH).c_str(), 0755);
115 mkdir(((std::string)WEB_LOGIN_DB_PATH + USERS_LOGIN_HISTORY_PATH).c_str(), 0755);
116 mkdir(((std::string)WEB_LOGIN_DB_PATH + USERS_PREFERENCES_PATH).c_str(), 0755);
119 __COUT__ <<
"FATAL USER DATABASE ERROR - failed to load!!!" << __E__;
121 loadSecuritySelection();
125 std::string user = DEFAULT_ADMIN_USERNAME;
126 if((i = searchUsersDatabaseForUsername(user)) == NOT_FOUND_IN_DATABASE)
128 __SS__ <<
"user: " << user <<
" is not found" << __E__;
129 __COUT_ERR__ << ss.str();
133 else if(UsersSaltVector[i] ==
135 securityType_ == SECURITY_TYPE_DIGEST_ACCESS)
137 char charTimeStr[10];
138 sprintf(charTimeStr,
"%d",
int(UsersAccountCreatedTimeVector[i] & 0xffff));
139 std::string tmpTimeStr = charTimeStr;
145 [](
const std::string& nac,
const std::string& user) {
146 WebUsers::NACDisplayThread(nac, user);
154 loadActiveSessions();
162 __COUT__ <<
"Done with Web Users initialization!" << __E__;
170 bool WebUsers::xmlRequestOnGateway(cgicc::Cgicc& cgi,
171 std::ostringstream* out,
176 WebUsers::initializeRequestUserInfo(cgi, userInfo);
180 if(!cookieCodeIsActiveForRequest(userInfo.cookieCode_,
181 &userInfo.groupPermissionLevelMap_,
184 !userInfo.automatedCommand_ ,
185 &userInfo.usernameWithLock_,
186 &userInfo.activeUserSessionIndex_))
188 *out << userInfo.cookieCode_;
189 goto HANDLE_ACCESS_FAILURE;
193 userInfo.getGroupPermissionLevel();
194 userInfo.username_ = UsersUsernameVector[userInfo.uid_];
195 userInfo.displayName_ = UsersDisplayNameVector[userInfo.uid_];
197 if(!WebUsers::checkRequestAccess(cgi, out, xmldoc, userInfo))
198 goto HANDLE_ACCESS_FAILURE;
202 HANDLE_ACCESS_FAILURE:
204 if(!userInfo.automatedCommand_)
205 __COUT_ERR__ <<
"Failed request (requestType = " << userInfo.requestType_
206 <<
"): " << out->str() << __E__;
214 void WebUsers::initializeRequestUserInfo(cgicc::Cgicc& cgi,
217 userInfo.ip_ = cgi.getEnvironment().getRemoteAddr();
220 userInfo.username_ =
"";
221 userInfo.displayName_ =
"";
222 userInfo.usernameWithLock_ =
"";
223 userInfo.activeUserSessionIndex_ = -1;
224 userInfo.setGroupPermissionLevels(
"");
234 bool WebUsers::checkRequestAccess(cgicc::Cgicc& cgi,
235 std::ostringstream* out,
239 const std::string& wizardModeSequence )
245 if(userInfo.requireSecurity_)
250 if(isWizardMode && wizardModeSequence.size() < 8)
253 *out << WebUsers::REQ_NO_PERMISSION_RESPONSE;
254 __COUT__ <<
"User (@" << userInfo.ip_ <<
") has attempted requestType '"
255 << userInfo.requestType_
256 <<
"' which requires sufficient security enabled. Please enable the "
258 " sequence of at least 8 characters."
263 else if(!isWizardMode &&
264 (userInfo.username_ == WebUsers::DEFAULT_ADMIN_USERNAME ||
265 userInfo.username_ == WebUsers::DEFAULT_ITERATOR_USERNAME ||
266 userInfo.username_ == WebUsers::DEFAULT_STATECHANGER_USERNAME))
269 *out << WebUsers::REQ_NO_PERMISSION_RESPONSE;
270 __COUT__ <<
"User (@" << userInfo.ip_ <<
") has attempted requestType '"
271 << userInfo.requestType_
272 <<
"' which requires sufficient security enabled. Please enable "
282 if(!userInfo.automatedCommand_)
284 __COUTT__ <<
"requestType ==========>>> " << userInfo.requestType_ << __E__;
285 __COUTTV__((
unsigned int)userInfo.permissionLevel_);
286 __COUTTV__((
unsigned int)userInfo.permissionsThreshold_);
290 if(!isWizardMode && !userInfo.allowNoUser_ &&
291 userInfo.cookieCode_.length() != WebUsers::COOKIE_CODE_LENGTH)
293 __COUT__ <<
"User (@" << userInfo.ip_
294 <<
") has invalid cookie code: " << userInfo.cookieCode_ << std::endl;
295 *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
299 if(!userInfo.allowNoUser_ &&
300 (userInfo.permissionLevel_ == 0 ||
301 userInfo.permissionLevel_ < userInfo.permissionsThreshold_))
303 *out << WebUsers::REQ_NO_PERMISSION_RESPONSE;
304 __COUT__ <<
"User (@" << userInfo.ip_
305 <<
") has insufficient permissions for requestType '"
306 << userInfo.requestType_
307 <<
"' : " << (
unsigned int)userInfo.permissionLevel_ <<
"<"
308 << (
unsigned int)userInfo.permissionsThreshold_ << std::endl;
315 userInfo.username_ = WebUsers::DEFAULT_ADMIN_USERNAME;
316 userInfo.displayName_ =
"Admin";
317 userInfo.usernameWithLock_ = userInfo.username_;
318 userInfo.activeUserSessionIndex_ = 0;
325 if(userInfo.allowNoUser_)
326 xmldoc->setHeader(WebUsers::REQ_ALLOW_NO_USER);
328 xmldoc->setHeader(userInfo.cookieCode_);
331 if(userInfo.allowNoUser_)
333 if(userInfo.automatedCommand_)
334 __COUT__ <<
"Allowing anonymous access." << __E__;
345 if((userInfo.checkLock_ || userInfo.requireLock_) &&
346 userInfo.usernameWithLock_ !=
"" &&
347 userInfo.usernameWithLock_ != userInfo.username_)
349 *out << WebUsers::REQ_USER_LOCKOUT_RESPONSE;
350 __COUT__ <<
"User '" << userInfo.username_ <<
"' is locked out. '"
351 << userInfo.usernameWithLock_ <<
"' has lock." << std::endl;
355 if(userInfo.requireLock_ && userInfo.usernameWithLock_ != userInfo.username_)
357 *out << WebUsers::REQ_LOCK_REQUIRED_RESPONSE;
358 __COUT__ <<
"User '" << userInfo.username_ <<
"' must have lock to proceed. ('"
359 << userInfo.usernameWithLock_ <<
"' has lock.)" << std::endl;
371 void WebUsers::saveActiveSessions()
375 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_ACTIVE_SESSIONS_FILE;
376 __COUT__ << fn << __E__;
378 FILE* fp = fopen(fn.c_str(),
"w");
381 __COUT_ERR__ <<
"Error! Persistent active sessions could not be saved to file: "
387 fprintf(fp,
"%d\n", version);
388 for(
unsigned int i = 0; i < ActiveSessionCookieCodeVector.size(); ++i)
396 fprintf(fp,
"%s\n", ActiveSessionCookieCodeVector[i].c_str());
397 fprintf(fp,
"%s\n", ActiveSessionIpVector[i].c_str());
398 fprintf(fp,
"%lu\n", ActiveSessionUserIdVector[i]);
399 fprintf(fp,
"%lu\n", ActiveSessionIndex[i]);
400 fprintf(fp,
"%ld\n", ActiveSessionStartTimeVector[i]);
403 __COUT__ <<
"ActiveSessionCookieCodeVector saved with size "
404 << ActiveSessionCookieCodeVector.size() << __E__;
412 void WebUsers::loadActiveSessions()
416 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_ACTIVE_SESSIONS_FILE;
417 __COUT__ << fn << __E__;
418 FILE* fp = fopen(fn.c_str(),
"r");
422 <<
"Persistent active sessions were not found to be loaded at file: " << fn
429 const int LINELEN = 1000;
431 fgets(line, LINELEN, fp);
432 sscanf(line,
"%d", &version);
435 __COUT__ <<
"Extracting active sessions..." << __E__;
438 while(fgets(line, LINELEN, fp))
441 line[strlen(line) - 1] =
'\0';
442 if(strlen(line) != COOKIE_CODE_LENGTH)
444 __COUT__ <<
"Illegal cookie code found: " << line << __E__;
449 ActiveSessionCookieCodeVector.push_back(line);
451 fgets(line, LINELEN, fp);
453 line[strlen(line) - 1] =
'\0';
454 ActiveSessionIpVector.push_back(line);
456 fgets(line, LINELEN, fp);
457 ActiveSessionUserIdVector.push_back(uint64_t());
460 &(ActiveSessionUserIdVector[ActiveSessionUserIdVector.size() - 1]));
462 fgets(line, LINELEN, fp);
463 ActiveSessionIndex.push_back(uint64_t());
464 sscanf(line,
"%lu", &(ActiveSessionIndex[ActiveSessionIndex.size() - 1]));
466 fgets(line, LINELEN, fp);
467 ActiveSessionStartTimeVector.push_back(time_t());
470 &(ActiveSessionStartTimeVector[ActiveSessionStartTimeVector.size() - 1]));
480 __COUT__ <<
"ActiveSessionCookieCodeVector loaded with size "
481 << ActiveSessionCookieCodeVector.size() << __E__;
485 fp = fopen(fn.c_str(),
"w");
494 bool WebUsers::loadDatabases()
499 const unsigned int LINE_LEN = 1000;
501 unsigned int i, si, c, len, f;
512 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)HASHES_DB_FILE;
513 __COUT__ << fn << __E__;
514 fp = fopen(fn.c_str(),
"r");
517 mkdir(((std::string)WEB_LOGIN_DB_PATH + (std::string)HASHES_DB_PATH).c_str(),
519 __COUT__ << ((std::string)WEB_LOGIN_DB_PATH + (std::string)HASHES_DB_PATH).c_str()
521 fp = fopen(fn.c_str(), "w");
524 __COUT__ << "Hashes database created: " << fn << __E__;
526 saveToDatabase(fp, HASHES_DB_GLOBAL_STRING, "", DB_SAVE_OPEN);
527 saveToDatabase(fp, HASHES_DB_GLOBAL_STRING, "", DB_SAVE_CLOSE);
534 while(fgets(line, LINE_LEN, fp))
536 if(strlen(line) < SHA512_DIGEST_LENGTH)
542 for(i = 0; i < len; ++i)
550 while(i < len && line[i] !=
'<')
561 HashesVector.push_back(&line[si]);
564 sscanf(&line[si],
"%lu", &tmpInt64);
565 HashesAccessTimeVector.push_back(tmpInt64);
569 __COUT__ << HashesAccessTimeVector.size() <<
" Hashes found." << __E__;
583 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_DB_FILE;
584 fp = fopen(fn.c_str(),
"r");
587 mkdir(((std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_DB_PATH).c_str(),
589 __COUT__ << ((std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_DB_PATH).c_str()
591 fp = fopen(fn.c_str(), "w");
594 __COUT__ << "Users database created: " << fn << __E__;
596 saveToDatabase(fp, USERS_DB_GLOBAL_STRING, "", DB_SAVE_OPEN);
598 sprintf(nidStr, "%lu", usersNextUserId_);
599 saveToDatabase(fp, USERS_DB_NEXT_UID_STRING, nidStr, DB_SAVE_OPEN_AND_CLOSE);
600 saveToDatabase(fp, USERS_DB_GLOBAL_STRING, "", DB_SAVE_CLOSE);
603 createNewAccount(DEFAULT_ADMIN_USERNAME,
604 DEFAULT_ADMIN_DISPLAY_NAME,
605 DEFAULT_ADMIN_EMAIL);
612 char salt[] =
"nextUserId";
613 while(fgets(line, LINE_LEN, fp))
615 if(strlen(line) < strlen(salt) * 2)
618 for(i = 0; i < strlen(salt); ++i)
619 if(line[i + 1] != salt[i])
622 if(i == strlen(salt))
627 while(i < LINE_LEN && line[i] !=
'\0' && line[i] !=
'<')
630 sscanf(&line[si],
"%lu", &usersNextUserId_);
635 __COUT__ <<
"Found Users database next user Id: " << usersNextUserId_ << __E__;
639 while(fgets(line, LINE_LEN, fp))
641 if(strlen(line) < 30)
649 __COUT__ <<
"Line buffer too small: " << len << __E__;
655 for(i = 0; i < len; ++i)
659 if(c == 0 || c % 2 == 1)
663 while(i < len && line[i] !=
'<')
673 UsersUsernameVector.push_back(&line[si]);
675 UsersDisplayNameVector.push_back(&line[si]);
677 UsersSaltVector.push_back(&line[si]);
680 sscanf(&line[si],
"%lu", &tmpInt64);
681 UsersUserIdVector.push_back(tmpInt64);
685 UsersPermissionsVector.push_back(
686 std::map<std::string, uint8_t>());
687 std::map<std::string, uint8_t>& lastPermissionsMap =
688 UsersPermissionsVector.back();
689 StringMacros::getMapFromString<uint8_t>(&line[si],
698 if(lastPermissionsMap.find(WebUsers::DEFAULT_USER_GROUP) ==
699 lastPermissionsMap.end())
703 sscanf(&line[si],
"%lu", &tmpInt64);
707 lastPermissionsMap.clear();
709 <<
"User '" << UsersUsernameVector.back()
710 <<
"' is not a member of the default user group '"
711 << WebUsers::DEFAULT_USER_GROUP
712 <<
".' For backward compatibility, permission level "
713 "assumed for default group (permission level := "
714 << tmpInt64 <<
")." << __E__;
715 lastPermissionsMap[WebUsers::DEFAULT_USER_GROUP] =
716 WebUsers::permissionLevel_t(tmpInt64);
722 << UsersUsernameVector.back()
723 <<
"' is not a member of the default user group '"
724 << WebUsers::DEFAULT_USER_GROUP
725 <<
".' Assuming user account is inactive (permission "
727 << WebUsers::PERMISSION_LEVEL_INACTIVE <<
")."
729 lastPermissionsMap[WebUsers::DEFAULT_USER_GROUP] =
730 WebUsers::PERMISSION_LEVEL_INACTIVE;
736 sscanf(&line[si],
"%lu", &tmpInt64);
737 UsersLastLoginAttemptVector.push_back(tmpInt64);
741 sscanf(&line[si],
"%lu", &tmpInt64);
742 UsersAccountCreatedTimeVector.push_back(tmpInt64);
746 sscanf(&line[si],
"%lu", &tmpInt64);
747 UsersLoginFailureCountVector.push_back(tmpInt64);
751 sscanf(&line[si],
"%lu", &tmpInt64);
752 UsersLastModifiedTimeVector.push_back(tmpInt64);
755 UsersLastModifierUsernameVector.push_back(&line[si]);
757 UsersUserEmailVector.push_back(&line[si]);
762 if(f && f != UsersDatabaseEntryFields.size() - 1)
768 <<
"FATAL ERROR - invalid user database found with field number "
778 __COUT__ <<
"Update database to current version - adding fields: "
779 << (UsersDatabaseEntryFields.size() - 1 - f) << __E__;
782 UsersLastModifiedTimeVector.push_back(0);
783 UsersLastModifierUsernameVector.push_back(
"");
787 UsersUserEmailVector.push_back(
"");
794 __COUT__ << UsersLastModifiedTimeVector.size() <<
" Users found." << __E__;
795 for(
size_t ii = 0; ii < UsersLastModifiedTimeVector.size(); ++ii)
797 __COUT__ <<
"User " << UsersUserIdVector[ii]
798 <<
": Name: " << UsersUsernameVector[ii]
799 <<
"\t\tDisplay Name: " << UsersDisplayNameVector[ii]
800 <<
"\t\tEmail: " << UsersUserEmailVector[ii] <<
"\t\tPermissions: "
801 << StringMacros::mapToString(UsersPermissionsVector[ii]) << __E__;
808 void WebUsers::saveToDatabase(FILE* fp,
809 const std::string& field,
810 const std::string& value,
817 std::string newLine = addNewLine ?
"\n" :
"";
819 if(type == DB_SAVE_OPEN_AND_CLOSE)
826 else if(type == DB_SAVE_OPEN)
827 fprintf(fp,
"<%s>%s%s", field.c_str(), value.c_str(), newLine.c_str());
828 else if(type == DB_SAVE_CLOSE)
829 fprintf(fp,
"</%s>%s", field.c_str(), newLine.c_str());
838 bool WebUsers::saveDatabaseToFile(uint8_t db)
840 __COUT__ <<
"Save Database: " << (int)db << __E__;
843 (std::string)WEB_LOGIN_DB_PATH +
844 ((db == DB_USERS) ? (std::string)USERS_DB_FILE : (std::string)HASHES_DB_FILE);
846 __COUT__ <<
"Save Database Filename: " << fn << __E__;
852 sprintf(dayAppend,
".%lu.bkup", time(0) / (3600 * 24));
853 std::string bkup_fn = (std::string)WEB_LOGIN_DB_PATH +
854 (std::string)WEB_LOGIN_BKUP_DB_PATH +
855 ((db == DB_USERS) ? (std::string)USERS_DB_FILE
856 : (std::
string)HASHES_DB_FILE) +
857 (std::
string)dayAppend;
859 __COUT__ << "Backup file: " << bkup_fn << __E__;
861 std::
string shell_command = "mv " + fn + " " + bkup_fn;
862 system(shell_command.c_str());
865 FILE* fp = fopen(fn.c_str(), "wb");
873 saveToDatabase(fp, USERS_DB_GLOBAL_STRING,
"", DB_SAVE_OPEN);
875 sprintf(fldStr,
"%lu", usersNextUserId_);
876 saveToDatabase(fp, USERS_DB_NEXT_UID_STRING, fldStr, DB_SAVE_OPEN_AND_CLOSE);
878 __COUT__ <<
"Saving " << UsersUsernameVector.size() <<
" Users." << __E__;
880 for(uint64_t i = 0; i < UsersUsernameVector.size(); ++i)
884 saveToDatabase(fp, USERS_DB_ENTRY_STRING,
"", DB_SAVE_OPEN,
false);
886 for(
unsigned int f = 0; f < UsersDatabaseEntryFields.size(); ++f)
891 UsersDatabaseEntryFields[f],
892 UsersUsernameVector[i],
893 DB_SAVE_OPEN_AND_CLOSE,
897 UsersDatabaseEntryFields[f],
898 UsersDisplayNameVector[i],
899 DB_SAVE_OPEN_AND_CLOSE,
903 UsersDatabaseEntryFields[f],
905 DB_SAVE_OPEN_AND_CLOSE,
909 sprintf(fldStr,
"%lu", UsersUserIdVector[i]);
911 UsersDatabaseEntryFields[f],
913 DB_SAVE_OPEN_AND_CLOSE,
918 UsersDatabaseEntryFields[f],
919 StringMacros::mapToString(UsersPermissionsVector[i],
922 DB_SAVE_OPEN_AND_CLOSE,
926 sprintf(fldStr,
"%lu", UsersLastLoginAttemptVector[i]);
928 UsersDatabaseEntryFields[f],
930 DB_SAVE_OPEN_AND_CLOSE,
935 sprintf(fldStr,
"%lu", UsersAccountCreatedTimeVector[i]);
937 UsersDatabaseEntryFields[f],
939 DB_SAVE_OPEN_AND_CLOSE,
944 sprintf(fldStr,
"%d", UsersLoginFailureCountVector[i]);
946 UsersDatabaseEntryFields[f],
948 DB_SAVE_OPEN_AND_CLOSE,
953 sprintf(fldStr,
"%lu", UsersLastModifiedTimeVector[i]);
955 UsersDatabaseEntryFields[f],
957 DB_SAVE_OPEN_AND_CLOSE,
962 UsersDatabaseEntryFields[f],
963 UsersLastModifierUsernameVector[i],
964 DB_SAVE_OPEN_AND_CLOSE,
968 UsersDatabaseEntryFields[f],
969 UsersUserEmailVector[i],
970 DB_SAVE_OPEN_AND_CLOSE,
974 saveToDatabase(fp, USERS_DB_ENTRY_STRING,
"", DB_SAVE_CLOSE);
977 saveToDatabase(fp, USERS_DB_GLOBAL_STRING,
"", DB_SAVE_CLOSE);
981 saveToDatabase(fp, HASHES_DB_GLOBAL_STRING,
"", DB_SAVE_OPEN);
983 __COUT__ <<
"Saving " << HashesVector.size() <<
" Hashes." << __E__;
984 for(uint64_t i = 0; i < HashesVector.size(); ++i)
986 __COUT__ <<
"Saving " << HashesVector[i] <<
" Hashes." << __E__;
987 saveToDatabase(fp, HASHES_DB_ENTRY_STRING,
"", DB_SAVE_OPEN,
false);
988 for(
unsigned int f = 0; f < HashesDatabaseEntryFields.size(); ++f)
992 HashesDatabaseEntryFields[f],
994 DB_SAVE_OPEN_AND_CLOSE,
998 sprintf(fldStr,
"%lu", HashesAccessTimeVector[i]);
1000 HashesDatabaseEntryFields[f],
1002 DB_SAVE_OPEN_AND_CLOSE,
1006 saveToDatabase(fp, HASHES_DB_ENTRY_STRING,
"", DB_SAVE_CLOSE);
1009 saveToDatabase(fp, HASHES_DB_GLOBAL_STRING,
"", DB_SAVE_CLOSE);
1023 bool WebUsers::createNewAccount(
const std::string& username,
1024 const std::string& displayName,
1025 const std::string& email)
1027 __COUT__ <<
"Creating account: " << username << __E__;
1030 if((i = searchUsersDatabaseForUsername(username)) != NOT_FOUND_IN_DATABASE ||
1031 username == WebUsers::DEFAULT_ITERATOR_USERNAME ||
1032 username == WebUsers::DEFAULT_STATECHANGER_USERNAME)
1035 __COUT_ERR__ <<
"Username '" << username <<
"' already exists" << __E__;
1040 UsersUsernameVector.push_back(username);
1041 UsersDisplayNameVector.push_back(displayName);
1042 UsersUserEmailVector.push_back(email);
1043 UsersSaltVector.push_back(
"");
1044 std::map<std::string , WebUsers::permissionLevel_t> initPermissions = {
1045 {WebUsers::DEFAULT_USER_GROUP,
1046 (UsersPermissionsVector.size() ? WebUsers::PERMISSION_LEVEL_NOVICE
1047 : WebUsers::PERMISSION_LEVEL_ADMIN)}};
1048 UsersPermissionsVector.push_back(initPermissions);
1050 UsersUserIdVector.push_back(usersNextUserId_++);
1051 if(usersNextUserId_ == (uint64_t)-1)
1053 __COUT__ <<
"usersNextUserId_ wrap around!! Too many users??? Notify Admins."
1055 usersNextUserId_ = 1;
1058 UsersLastLoginAttemptVector.push_back(0);
1059 UsersLoginFailureCountVector.push_back(0);
1060 UsersAccountCreatedTimeVector.push_back(time(0));
1061 UsersLastModifiedTimeVector.push_back(0);
1062 UsersLastModifierUsernameVector.push_back(
"");
1064 return saveDatabaseToFile(DB_USERS);
1073 bool WebUsers::deleteAccount(
const std::string& username,
const std::string& displayName)
1075 uint64_t i = searchUsersDatabaseForUsername(username);
1076 if(i == NOT_FOUND_IN_DATABASE)
1078 if(UsersDisplayNameVector[i] != displayName)
1083 UsersUsernameVector.erase(UsersUsernameVector.begin() + i);
1084 UsersUserEmailVector.erase(UsersUserEmailVector.begin() + i);
1085 UsersDisplayNameVector.erase(UsersDisplayNameVector.begin() + i);
1086 UsersSaltVector.erase(UsersSaltVector.begin() + i);
1087 UsersPermissionsVector.erase(UsersPermissionsVector.begin() + i);
1088 UsersUserIdVector.erase(UsersUserIdVector.begin() + i);
1089 UsersLastLoginAttemptVector.erase(UsersLastLoginAttemptVector.begin() + i);
1090 UsersAccountCreatedTimeVector.erase(UsersAccountCreatedTimeVector.begin() + i);
1091 UsersLoginFailureCountVector.erase(UsersLoginFailureCountVector.begin() + i);
1092 UsersLastModifierUsernameVector.erase(UsersLastModifierUsernameVector.begin() + i);
1093 UsersLastModifiedTimeVector.erase(UsersLastModifiedTimeVector.begin() + i);
1096 return saveDatabaseToFile(DB_USERS);
1100 unsigned int WebUsers::hexByteStrToInt(
const char* h)
1103 char hs[3] = {h[0], h[1],
'\0'};
1104 sscanf(hs,
"%X", &rv);
1109 void WebUsers::intToHexStr(
unsigned char i,
char* h) { sprintf(h,
"%2.2X", i); }
1121 uint64_t WebUsers::attemptActiveSession(
const std::string& uuid,
1122 std::string& jumbledUser,
1123 const std::string& jumbledPw,
1124 std::string& newAccountCode,
1125 const std::string& ip)
1128 if(!checkIpAccess(ip))
1130 __COUT_ERR__ <<
"rejected ip: " << ip << __E__;
1131 return NOT_FOUND_IN_DATABASE;
1134 cleanupExpiredEntries();
1136 if(!CareAboutCookieCodes_)
1138 uint64_t uid = getAdminUserID();
1139 jumbledUser = getUsersDisplayName(uid);
1140 newAccountCode = genCookieCode();
1147 if((i = searchLoginSessionDatabaseForUUID(uuid)) == NOT_FOUND_IN_DATABASE)
1149 __COUT_ERR__ <<
"uuid: " << uuid <<
" is not found" << __E__;
1150 newAccountCode =
"1";
1152 incrementIpBlacklistCount(ip);
1154 return NOT_FOUND_IN_DATABASE;
1156 ++LoginSessionAttemptsVector[i];
1158 std::string user = dejumble(jumbledUser, LoginSessionIdVector[i]);
1160 std::string pw = dejumble(jumbledPw, LoginSessionIdVector[i]);
1163 if((i = searchUsersDatabaseForUsername(user)) == NOT_FOUND_IN_DATABASE)
1165 __COUT_ERR__ <<
"user: " << user <<
" is not found" << __E__;
1167 incrementIpBlacklistCount(ip);
1169 return NOT_FOUND_IN_DATABASE;
1172 ipBlacklistCounts_[ip] = 0;
1174 UsersLastLoginAttemptVector[i] = time(0);
1176 if(isInactiveForGroup(UsersPermissionsVector[i]))
1178 __MCOUT_ERR__(
"User '" << user
1179 <<
"' account INACTIVE (could be due to failed logins)"
1181 return NOT_FOUND_IN_DATABASE;
1184 if(UsersSaltVector[i] ==
"")
1186 __MCOUT__(
"First login attempt for user: " << user << __E__);
1188 char charTimeStr[10];
1189 sprintf(charTimeStr,
"%d",
int(UsersAccountCreatedTimeVector[i] & 0xffff));
1190 std::string tmpTimeStr = charTimeStr;
1191 if(newAccountCode != tmpTimeStr)
1193 __COUT__ <<
"New account code did not match: " << tmpTimeStr
1194 <<
" != " << newAccountCode << __E__;
1195 saveDatabaseToFile(DB_USERS);
1196 return NOT_FOUND_IN_DATABASE;
1202 while(!addToHashesDatabase(
1203 sha512(user, pw, UsersSaltVector[i])))
1208 UsersSaltVector[i] =
"";
1211 __COUT__ <<
"\tHash added: " << HashesVector[HashesVector.size() - 1] << __E__;
1215 std::string salt = UsersSaltVector[i];
1217 if(searchHashesDatabaseForHash(sha512(user, pw, salt)) == NOT_FOUND_IN_DATABASE)
1219 __COUT__ <<
"Failed login for " << user <<
" with permissions "
1220 << StringMacros::mapToString(UsersPermissionsVector[i]) << __E__;
1222 ++UsersLoginFailureCountVector[i];
1223 if(UsersLoginFailureCountVector[i] >= USERS_MAX_LOGIN_FAILURES)
1224 UsersPermissionsVector[i][WebUsers::DEFAULT_USER_GROUP] =
1225 WebUsers::PERMISSION_LEVEL_INACTIVE;
1227 __COUT_INFO__ <<
"User/pw for user '" << user
1228 <<
"' was not correct (Failed Attempt #"
1229 << (int)UsersLoginFailureCountVector[i] <<
" of "
1230 << (
int)USERS_MAX_LOGIN_FAILURES << ")." << __E__;
1232 __COUTV__(isInactiveForGroup(UsersPermissionsVector[i]));
1233 if(isInactiveForGroup(UsersPermissionsVector[i]))
1234 __MCOUT_INFO__("Account '"
1236 << "' has been marked inactive due to too many failed "
1237 "login attempts (Failed Attempt
#"
1238 << (int)UsersLoginFailureCountVector[i]
1239 <<
")! Note only admins can reactivate accounts."
1242 saveDatabaseToFile(DB_USERS);
1243 return NOT_FOUND_IN_DATABASE;
1247 __MCOUT_INFO__(
"Login successful for: " << user << __E__);
1249 UsersLoginFailureCountVector[i] = 0;
1252 for(
int h = 0; h < 2; ++h)
1254 std::string fn = (std::string)WEB_LOGIN_DB_PATH +
1255 (std::string)USERS_LOGIN_HISTORY_PATH +
1256 (h ? USERS_GLOBAL_HISTORY_FILE : UsersUsernameVector[i]) +
"." +
1257 (std::string)USERS_LOGIN_HISTORY_FILETYPE;
1261 if(histXml.loadXmlDocument(fn))
1263 while(histXml.getChildrenCount() + 1 >
1264 (h ? USERS_GLOBAL_HISTORY_SIZE : USERS_LOGIN_HISTORY_SIZE))
1265 histXml.removeDataElement();
1268 __COUT__ <<
"No previous login history found." << __E__;
1274 "Time=%lu Username=%s Permissions=%s UID=%lu",
1276 UsersUsernameVector[i].c_str(),
1277 StringMacros::mapToString(UsersPermissionsVector[i]).c_str(),
1278 UsersUserIdVector[i]);
1281 "Time=%lu displayName=%s Permissions=%s UID=%lu",
1283 UsersDisplayNameVector[i].c_str(),
1284 StringMacros::mapToString(UsersPermissionsVector[i]).c_str(),
1285 UsersUserIdVector[i]);
1286 histXml.addTextElementToData(PREF_XML_LOGIN_HISTORY_FIELD, entryStr);
1289 histXml.saveXmlDocument(fn);
1293 saveDatabaseToFile(DB_USERS);
1294 jumbledUser = UsersDisplayNameVector[i];
1295 newAccountCode = createNewActiveSession(UsersUserIdVector[i],
1297 return UsersUserIdVector[i];
1306 uint64_t WebUsers::attemptActiveSessionWithCert(
const std::string& uuid,
1308 std::string& cookieCode,
1310 const std::string& ip)
1312 if(!checkIpAccess(ip))
1314 __COUT_ERR__ <<
"rejected ip: " << ip << __E__;
1315 return NOT_FOUND_IN_DATABASE;
1318 cleanupExpiredEntries();
1320 if(!CareAboutCookieCodes_)
1322 uint64_t uid = getAdminUserID();
1323 email = getUsersDisplayName(uid);
1324 cookieCode = genCookieCode();
1330 __COUT__ <<
"Rejecting logon with blank fingerprint" << __E__;
1332 incrementIpBlacklistCount(ip);
1334 return NOT_FOUND_IN_DATABASE;
1340 if((i = searchLoginSessionDatabaseForUUID(uuid)) == NOT_FOUND_IN_DATABASE)
1342 __COUT__ <<
"uuid: " << uuid <<
" is not found" << __E__;
1345 incrementIpBlacklistCount(ip);
1347 return NOT_FOUND_IN_DATABASE;
1349 ++LoginSessionAttemptsVector[i];
1351 email = getUserEmailFromFingerprint(email);
1352 __COUT__ <<
"DejumbledEmail = " << email << __E__;
1355 __COUT__ <<
"Rejecting logon with unknown fingerprint" << __E__;
1357 incrementIpBlacklistCount(ip);
1359 return NOT_FOUND_IN_DATABASE;
1363 if((i = searchUsersDatabaseForUserEmail(email)) == NOT_FOUND_IN_DATABASE)
1365 __COUT__ <<
"email: " << email <<
" is not found" << __E__;
1367 incrementIpBlacklistCount(ip);
1369 return NOT_FOUND_IN_DATABASE;
1372 ipBlacklistCounts_[ip] = 0;
1374 user = getUsersUsername(i);
1376 UsersLastLoginAttemptVector[i] = time(0);
1377 if(isInactiveForGroup(UsersPermissionsVector[i]))
1379 __MCOUT__(
"User '" << user
1380 <<
"' account INACTIVE (could be due to failed logins)."
1382 return NOT_FOUND_IN_DATABASE;
1385 if(UsersSaltVector[i] ==
"")
1387 return NOT_FOUND_IN_DATABASE;
1390 __MCOUT__(
"Login successful for: " << user << __E__);
1392 UsersLoginFailureCountVector[i] = 0;
1395 for(
int h = 0; h < 2; ++h)
1397 std::string fn = (std::string)WEB_LOGIN_DB_PATH +
1398 (std::string)USERS_LOGIN_HISTORY_PATH +
1399 (h ? USERS_GLOBAL_HISTORY_FILE : UsersUsernameVector[i]) +
"." +
1400 (std::string)USERS_LOGIN_HISTORY_FILETYPE;
1404 if(histXml.loadXmlDocument(fn))
1406 while(histXml.getChildrenCount() + 1 >
1407 (h ? USERS_GLOBAL_HISTORY_SIZE : USERS_LOGIN_HISTORY_SIZE))
1408 histXml.removeDataElement();
1411 __COUT__ <<
"No previous login history found." << __E__;
1417 "Time=%lu Username=%s Permissions=%s UID=%lu",
1419 UsersUsernameVector[i].c_str(),
1420 StringMacros::mapToString(UsersPermissionsVector[i]).c_str(),
1421 UsersUserIdVector[i]);
1424 "Time=%lu displayName=%s Permissions=%s UID=%lu",
1426 UsersDisplayNameVector[i].c_str(),
1427 StringMacros::mapToString(UsersPermissionsVector[i]).c_str(),
1428 UsersUserIdVector[i]);
1429 histXml.addTextElementToData(PREF_XML_LOGIN_HISTORY_FIELD, entryStr);
1432 histXml.saveXmlDocument(fn);
1436 saveDatabaseToFile(DB_USERS);
1437 email = UsersDisplayNameVector[i];
1438 cookieCode = createNewActiveSession(UsersUserIdVector[i],
1440 return UsersUserIdVector[i];
1446 uint64_t WebUsers::searchActiveSessionDatabaseForCookie(
1447 const std::string& cookieCode)
const
1450 for(; i < ActiveSessionCookieCodeVector.size(); ++i)
1451 if(ActiveSessionCookieCodeVector[i] == cookieCode)
1453 return (i == ActiveSessionCookieCodeVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1459 bool WebUsers::isUsernameActive(
const std::string& username)
const
1462 if((u = searchUsersDatabaseForUsername(username)) == NOT_FOUND_IN_DATABASE)
1464 return isUserIdActive(UsersUserIdVector[u]);
1470 bool WebUsers::isUserIdActive(uint64_t uid)
const
1473 for(; i < ActiveSessionUserIdVector.size(); ++i)
1474 if(ActiveSessionUserIdVector[i] == uid)
1482 uint64_t WebUsers::searchUsersDatabaseForUsername(
const std::string& username)
const
1485 for(; i < UsersUsernameVector.size(); ++i)
1486 if(UsersUsernameVector[i] == username)
1488 return (i == UsersUsernameVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1494 uint64_t WebUsers::searchUsersDatabaseForUserEmail(
const std::string& useremail)
const
1497 for(; i < UsersUserEmailVector.size(); ++i)
1498 if(UsersUserEmailVector[i] == useremail)
1500 return (i == UsersUserEmailVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1506 uint64_t WebUsers::searchUsersDatabaseForUserId(uint64_t uid)
const
1509 for(; i < UsersUserIdVector.size(); ++i)
1510 if(UsersUserIdVector[i] == uid)
1512 return (i == UsersUserIdVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1518 uint64_t WebUsers::searchLoginSessionDatabaseForUUID(
const std::string& uuid)
const
1521 for(; i < LoginSessionUUIDVector.size(); ++i)
1522 if(LoginSessionUUIDVector[i] == uuid)
1524 return (i == LoginSessionUUIDVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1530 uint64_t WebUsers::searchHashesDatabaseForHash(
const std::string& hash)
1535 for(; i < HashesVector.size(); ++i)
1536 if(HashesVector[i] == hash)
1541 if(i < HashesAccessTimeVector
1543 HashesAccessTimeVector.push_back(
1544 (time(0) + (rand() % 2 ? 1 : -1) * (rand() % 30 * 24 * 60 * 60)) &
1545 0x0FFFFFFFFFE000000);
1548 return (i == HashesVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1555 bool WebUsers::addToHashesDatabase(
const std::string& hash)
1557 if(searchHashesDatabaseForHash(hash) != NOT_FOUND_IN_DATABASE)
1559 __COUT__ <<
"Hash collision: " << hash << __E__;
1562 HashesVector.push_back(hash);
1563 HashesAccessTimeVector.push_back(
1564 (time(0) + (rand() % 2 ? 1 : -1) * (rand() % 30 * 24 * 60 * 60)) &
1565 0x0FFFFFFFFFE000000);
1568 return saveDatabaseToFile(DB_HASHES);
1573 std::string WebUsers::genCookieCode()
1576 std::string cc =
"";
1577 for(uint32_t i = 0; i < COOKIE_CODE_LENGTH / 2; ++i)
1579 intToHexStr(rand(), hexStr);
1587 void WebUsers::removeLoginSessionEntry(
unsigned int i)
1589 LoginSessionIdVector.erase(LoginSessionIdVector.begin() + i);
1590 LoginSessionUUIDVector.erase(LoginSessionUUIDVector.begin() + i);
1591 LoginSessionIpVector.erase(LoginSessionIpVector.begin() + i);
1592 LoginSessionStartTimeVector.erase(LoginSessionStartTimeVector.begin() + i);
1593 LoginSessionAttemptsVector.erase(LoginSessionAttemptsVector.begin() + i);
1600 std::string WebUsers::createNewActiveSession(uint64_t uid,
1601 const std::string& ip,
1605 ActiveSessionCookieCodeVector.push_back(genCookieCode());
1606 ActiveSessionIpVector.push_back(ip);
1607 ActiveSessionUserIdVector.push_back(uid);
1608 ActiveSessionStartTimeVector.push_back(time(0));
1611 ActiveSessionIndex.push_back(asIndex);
1616 for(uint64_t j = 0; j < ActiveSessionIndex.size(); ++j)
1617 if(ActiveSessionUserIdVector[j] == uid &&
1618 max < ActiveSessionIndex[j])
1619 max = ActiveSessionIndex[j];
1621 ActiveSessionIndex.push_back(max ? max + 1 : 1);
1624 return ActiveSessionCookieCodeVector[ActiveSessionCookieCodeVector.size() - 1];
1629 void WebUsers::removeActiveSessionEntry(
unsigned int i)
1631 ActiveSessionCookieCodeVector.erase(ActiveSessionCookieCodeVector.begin() + i);
1632 ActiveSessionIpVector.erase(ActiveSessionIpVector.begin() + i);
1633 ActiveSessionUserIdVector.erase(ActiveSessionUserIdVector.begin() + i);
1634 ActiveSessionStartTimeVector.erase(ActiveSessionStartTimeVector.begin() + i);
1635 ActiveSessionIndex.erase(ActiveSessionIndex.begin() + i);
1662 std::string WebUsers::refreshCookieCode(
unsigned int i,
bool enableRefresh)
1665 for(uint64_t j = ActiveSessionUserIdVector.size() - 1; j != (uint64_t)-1;
1667 if(ActiveSessionUserIdVector[j] == ActiveSessionUserIdVector[i] &&
1668 ActiveSessionIndex[j] ==
1669 ActiveSessionIndex[i])
1674 if(enableRefresh && (time(0) - ActiveSessionStartTimeVector[j] >
1675 ACTIVE_SESSION_EXPIRATION_TIME / 2))
1679 ActiveSessionStartTimeVector[j] =
1680 time(0) - ACTIVE_SESSION_EXPIRATION_TIME +
1681 ACTIVE_SESSION_COOKIE_OVERLAP_TIME;
1687 return createNewActiveSession(ActiveSessionUserIdVector[i],
1688 ActiveSessionIpVector[i],
1689 ActiveSessionIndex[i]);
1692 return ActiveSessionCookieCodeVector[j];
1703 uint64_t WebUsers::isCookieCodeActiveForLogin(
const std::string& uuid,
1704 std::string& cookieCode,
1705 std::string& username)
1707 if(!CareAboutCookieCodes_)
1708 return getAdminUserID();
1714 if(!ActiveSessionStartTimeVector.size())
1715 return NOT_FOUND_IN_DATABASE;
1720 if((i = searchLoginSessionDatabaseForUUID(uuid)) == NOT_FOUND_IN_DATABASE)
1722 __COUT__ <<
"uuid not found: " << uuid << __E__;
1723 return NOT_FOUND_IN_DATABASE;
1727 dejumble(username, LoginSessionIdVector[i]);
1730 if((i = searchActiveSessionDatabaseForCookie(cookieCode)) == NOT_FOUND_IN_DATABASE)
1732 __COUT__ <<
"Cookie code not found" << __E__;
1733 return NOT_FOUND_IN_DATABASE;
1737 if((j = searchUsersDatabaseForUserId(ActiveSessionUserIdVector[i])) ==
1738 NOT_FOUND_IN_DATABASE)
1740 __COUT__ <<
"User ID not found" << __E__;
1741 return NOT_FOUND_IN_DATABASE;
1745 if(UsersUsernameVector[j] != username)
1747 __COUT__ <<
"cookieCode: " << cookieCode <<
" was.." << __E__;
1748 __COUT__ <<
"username: " << username <<
" is not found" << __E__;
1749 return NOT_FOUND_IN_DATABASE;
1752 username = UsersDisplayNameVector[j];
1753 cookieCode = refreshCookieCode(i);
1754 return UsersUserIdVector[j];
1760 uint64_t WebUsers::getActiveSessionCountForUser(uint64_t uid)
1763 std::vector<uint64_t> uniqueAsi;
1766 for(i = 0; i < ActiveSessionUserIdVector.size(); ++i)
1767 if(ActiveSessionUserIdVector[i] == uid)
1772 for(j = 0; j < uniqueAsi.size(); ++j)
1773 if(uniqueAsi[j] == ActiveSessionIndex[i])
1780 uniqueAsi.push_back(ActiveSessionIndex[i]);
1783 __COUT__ <<
"Found " << uniqueAsi.size() <<
" active sessions for uid " << uid
1786 return uniqueAsi.size();
1795 bool WebUsers::checkIpAccess(
const std::string& ip)
1800 FILE* fp = fopen((IP_ACCEPT_FILE).c_str(),
"r");
1806 while(fgets(line, 300, fp))
1810 if(len > 2 && line[len - 1] ==
'\n')
1811 line[len - 1] =
'\0';
1812 if(StringMacros::wildCardMatch(ip, line))
1819 fp = fopen((IP_REJECT_FILE).c_str(),
"r");
1822 while(fgets(line, 300, fp))
1826 if(len > 2 && line[len - 1] ==
'\n')
1827 line[len - 1] =
'\0';
1828 if(StringMacros::wildCardMatch(ip, line))
1835 fp = fopen((IP_BLACKLIST_FILE).c_str(),
"r");
1838 while(fgets(line, 300, fp))
1842 if(len > 2 && line[len - 1] ==
'\n')
1843 line[len - 1] =
'\0';
1844 if(StringMacros::wildCardMatch(ip, line))
1857 void WebUsers::incrementIpBlacklistCount(
const std::string& ip)
1860 auto it = ipBlacklistCounts_.find(ip);
1861 if(it == ipBlacklistCounts_.end())
1863 __COUT__ <<
"First error for ip '" << ip <<
"'" << __E__;
1864 ipBlacklistCounts_[ip] = 1;
1870 if(it->second >= IP_BLACKLIST_COUNT_THRESHOLD)
1872 __MCOUT__(
"Adding IP '" << ip <<
"' to blacklist!" << __E__);
1875 FILE* fp = fopen((IP_BLACKLIST_FILE).c_str(),
"a");
1878 __SS__ <<
"IP black list file '" << IP_BLACKLIST_FILE
1879 <<
"' could not be opened." << __E__;
1880 __MCOUT_ERR__(ss.str());
1883 fprintf(fp,
"%s\n", ip.c_str());
1891 std::string WebUsers::getUsersDisplayName(uint64_t uid)
1894 if((i = searchUsersDatabaseForUserId(uid)) == NOT_FOUND_IN_DATABASE)
1896 return UsersDisplayNameVector[i];
1901 std::string WebUsers::getUsersUsername(uint64_t uid)
1904 if((i = searchUsersDatabaseForUserId(uid)) == NOT_FOUND_IN_DATABASE)
1906 return UsersUsernameVector[i];
1920 uint64_t WebUsers::cookieCodeLogout(
const std::string& cookieCode,
1921 bool logoutOtherUserSessions,
1923 const std::string& ip)
1928 if((i = searchActiveSessionDatabaseForCookie(cookieCode)) == NOT_FOUND_IN_DATABASE)
1930 __COUT__ <<
"Cookie code not found" << __E__;
1932 incrementIpBlacklistCount(ip);
1934 return NOT_FOUND_IN_DATABASE;
1937 ipBlacklistCounts_[ip] = 0;
1940 if(ActiveSessionIpVector[i] != ip)
1942 __COUT__ <<
"IP does not match active session" << __E__;
1943 return NOT_FOUND_IN_DATABASE;
1952 uint64_t asi = ActiveSessionIndex[i];
1953 uint64_t uid = ActiveSessionUserIdVector[i];
1956 uint64_t logoutCount = 0;
1959 while(i < ActiveSessionIndex.size())
1961 if((logoutOtherUserSessions && ActiveSessionUserIdVector[i] == uid &&
1962 ActiveSessionIndex[i] != asi) ||
1963 (!logoutOtherUserSessions && ActiveSessionUserIdVector[i] == uid &&
1964 ActiveSessionIndex[i] == asi))
1966 __COUT__ <<
"Logging out of active session " << ActiveSessionUserIdVector[i]
1967 <<
"-" << ActiveSessionIndex[i] << __E__;
1968 removeActiveSessionEntry(i);
1975 __COUT__ <<
"Found and removed active session count = " << logoutCount << __E__;
1982 bool WebUsers::getUserInfoForCookie(std::string& cookieCode,
1983 std::string* userName,
1984 std::string* displayName,
1985 uint64_t* activeSessionIndex)
1992 if(!CareAboutCookieCodes_)
1994 uint64_t uid = getAdminUserID();
1996 *userName = getUsersUsername(uid);
1998 *displayName = getUsersDisplayName(uid);
1999 if(activeSessionIndex)
2000 *activeSessionIndex = -1;
2007 if((i = searchActiveSessionDatabaseForCookie(cookieCode)) == NOT_FOUND_IN_DATABASE)
2009 __COUT__ <<
"cookieCode NOT_FOUND_IN_DATABASE" << __E__;
2014 if((j = searchUsersDatabaseForUserId(ActiveSessionUserIdVector[i])) ==
2015 NOT_FOUND_IN_DATABASE)
2017 __COUT__ <<
"ActiveSessionUserIdVector NOT_FOUND_IN_DATABASE" << __E__;
2022 *userName = UsersUsernameVector[j];
2024 *displayName = UsersDisplayNameVector[j];
2025 if(activeSessionIndex)
2026 *activeSessionIndex = ActiveSessionIndex[i];
2043 bool WebUsers::cookieCodeIsActiveForRequest(
2044 std::string& cookieCode,
2045 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>* userPermissions,
2047 const std::string& ip,
2049 std::string* userWithLock,
2050 uint64_t* activeUserSessionIndex)
2055 if(!checkIpAccess(ip))
2057 __COUT_ERR__ <<
"User IP rejected." << __E__;
2058 cookieCode = REQ_NO_LOGIN_RESPONSE;
2062 cleanupExpiredEntries();
2069 if(!CareAboutCookieCodes_)
2073 std::map<std::string , WebUsers::permissionLevel_t>(
2074 {{WebUsers::DEFAULT_USER_GROUP, WebUsers::PERMISSION_LEVEL_ADMIN}});
2076 *uid = getAdminUserID();
2078 *userWithLock = usersUsernameWithLock_;
2079 if(activeUserSessionIndex)
2080 *activeUserSessionIndex = -1;
2082 if(cookieCode.size() != COOKIE_CODE_LENGTH)
2083 cookieCode = genCookieCode();
2090 if((i = searchActiveSessionDatabaseForCookie(cookieCode)) == NOT_FOUND_IN_DATABASE)
2092 __COUT_ERR__ <<
"Cookie code not found" << __E__;
2093 cookieCode = REQ_NO_LOGIN_RESPONSE;
2095 incrementIpBlacklistCount(ip);
2100 ipBlacklistCounts_[ip] = 0;
2103 if(ip !=
"0" && ActiveSessionIpVector[i] != ip)
2105 __COUTV__(ActiveSessionIpVector[i]);
2107 __COUT_ERR__ <<
"IP does not match active session." << __E__;
2108 cookieCode = REQ_NO_LOGIN_RESPONSE;
2113 if((j = searchUsersDatabaseForUserId(ActiveSessionUserIdVector[i])) ==
2114 NOT_FOUND_IN_DATABASE)
2116 __COUT_ERR__ <<
"User ID not found" << __E__;
2117 cookieCode = REQ_NO_LOGIN_RESPONSE;
2121 std::map<std::string , WebUsers::permissionLevel_t> tmpPerm =
2122 getPermissionsForUser(UsersUserIdVector[j]);
2124 if(isInactiveForGroup(tmpPerm))
2126 cookieCode = REQ_NO_PERMISSION_RESPONSE;
2132 *userPermissions = tmpPerm;
2134 *uid = UsersUserIdVector[j];
2136 *userWithLock = usersUsernameWithLock_;
2137 if(activeUserSessionIndex)
2138 *activeUserSessionIndex = ActiveSessionIndex[i];
2140 cookieCode = refreshCookieCode(i, refresh);
2152 void WebUsers::cleanupExpiredEntries(std::vector<std::string>* loggedOutUsernames)
2157 if(loggedOutUsernames)
2159 for(i = 0; i < UsersLoggedOutUsernames_.size(); ++i)
2160 loggedOutUsernames->push_back(UsersLoggedOutUsernames_[i]);
2161 UsersLoggedOutUsernames_.clear();
2165 for(i = 0; i < LoginSessionStartTimeVector.size(); ++i)
2166 if(LoginSessionStartTimeVector[i] + LOGIN_SESSION_EXPIRATION_TIME <
2168 LoginSessionAttemptsVector[i] > LOGIN_SESSION_ATTEMPTS_MAX)
2174 removeLoginSessionEntry(i);
2187 for(i = 0; i < ActiveSessionStartTimeVector.size(); ++i)
2188 if(ActiveSessionStartTimeVector[i] + ACTIVE_SESSION_EXPIRATION_TIME <=
2197 tmpUid = ActiveSessionUserIdVector[i];
2198 removeActiveSessionEntry(i);
2200 if(!isUserIdActive(tmpUid))
2203 if(loggedOutUsernames)
2204 loggedOutUsernames->push_back(
2205 UsersUsernameVector[searchUsersDatabaseForUserId(tmpUid)]);
2207 UsersLoggedOutUsernames_.push_back(
2208 UsersUsernameVector[searchUsersDatabaseForUserId(tmpUid)]);
2229 if(CareAboutCookieCodes_ &&
2230 !isUsernameActive(usersUsernameWithLock_))
2231 usersUsernameWithLock_ =
"";
2241 std::string WebUsers::createNewLoginSession(
const std::string& UUID,
2242 const std::string& ip)
2248 for(; i < LoginSessionUUIDVector.size(); ++i)
2249 if(LoginSessionUUIDVector[i] == UUID)
2252 if(i != LoginSessionUUIDVector.size())
2254 __COUT_ERR__ <<
"UUID: " << UUID <<
" is not unique" << __E__;
2259 LoginSessionUUIDVector.push_back(UUID);
2263 std::string sid =
"";
2264 for(i = 0; i < SESSION_ID_LENGTH / 2; ++i)
2266 intToHexStr(rand(), hexStr);
2269 LoginSessionIdVector.push_back(sid);
2270 LoginSessionIpVector.push_back(ip);
2271 LoginSessionStartTimeVector.push_back(time(0));
2272 LoginSessionAttemptsVector.push_back(0);
2282 std::string WebUsers::sha512(
const std::string& user,
2283 const std::string& password,
2286 SHA512_CTX sha512_context;
2291 SHA512_Init(&sha512_context);
2293 for(
unsigned int i = 0; i < 8; ++i)
2294 sha512_context.h[i] += rand();
2296 for(
unsigned int i = 0; i <
sizeof(SHA512_CTX); ++i)
2298 intToHexStr((uint8_t)(((uint8_t*)(&sha512_context))[i]), hexStr);
2300 salt.append(hexStr);
2308 for(
unsigned int i = 0; i <
sizeof(SHA512_CTX); ++i)
2309 ((uint8_t*)(&sha512_context))[i] = hexByteStrToInt(&(salt.c_str()[i * 2]));
2312 std::string strToHash = salt + user + password;
2315 unsigned char hash[SHA512_DIGEST_LENGTH];
2317 char retHash[SHA512_DIGEST_LENGTH * 2 + 1];
2321 SHA512_Update(&sha512_context, strToHash.c_str(), strToHash.length());
2323 SHA512_Final(hash, &sha512_context);
2327 for(i = 0; i < SHA512_DIGEST_LENGTH; i++)
2328 sprintf(retHash + (i * 2),
"%02x", hash[i]);
2331 retHash[SHA512_DIGEST_LENGTH * 2] =
'\0';
2342 std::string WebUsers::dejumble(
const std::string& u,
const std::string& s)
2344 if(s.length() != SESSION_ID_LENGTH)
2347 const int ss = s.length() / 2;
2348 int p = hexByteStrToInt(&(s.c_str()[0])) % ss;
2349 int n = hexByteStrToInt(&(s.c_str()[p * 2])) % ss;
2350 int len = (hexByteStrToInt(&(u.c_str()[p * 2])) - p - n + ss * 3) % ss;
2352 std::vector<bool> x(ss);
2353 for(
int i = 0; i < ss; ++i)
2357 int c = hexByteStrToInt(&(u.c_str()[p * 2]));
2359 std::string user =
"";
2361 for(
int l = 0; l < len; ++l)
2363 p = (p + hexByteStrToInt(&(s.c_str()[p * 2]))) % ss;
2367 n = hexByteStrToInt(&(s.c_str()[p * 2]));
2368 user.append(1, (hexByteStrToInt(&(u.c_str()[p * 2])) - c - n + ss * 4) % ss);
2369 c = hexByteStrToInt(&(u.c_str()[p * 2]));
2378 std::map<std::string , WebUsers::permissionLevel_t>
2379 WebUsers::getPermissionsForUser(uint64_t uid)
2382 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2384 if(userIndex < UsersPermissionsVector.size())
2385 return UsersPermissionsVector[userIndex];
2388 std::map<std::string , WebUsers::permissionLevel_t> retErrorMap;
2389 retErrorMap[WebUsers::DEFAULT_USER_GROUP] = WebUsers::PERMISSION_LEVEL_INACTIVE;
2394 WebUsers::permissionLevel_t WebUsers::getPermissionLevelForGroup(
2395 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap,
2396 const std::string& groupName)
2398 auto it = permissionMap.find(groupName);
2399 if(it == permissionMap.end())
2401 __COUT__ <<
"Group name '" << groupName
2402 <<
"' not found - assuming inactive user in this group." << __E__;
2403 return WebUsers::PERMISSION_LEVEL_INACTIVE;
2409 bool WebUsers::isInactiveForGroup(
2410 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap,
2411 const std::string& groupName)
2413 return getPermissionLevelForGroup(permissionMap, groupName) ==
2414 WebUsers::PERMISSION_LEVEL_INACTIVE;
2418 bool WebUsers::isAdminForGroup(
2419 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap,
2420 const std::string& groupName)
2422 return getPermissionLevelForGroup(permissionMap, groupName) ==
2423 WebUsers::PERMISSION_LEVEL_ADMIN;
2429 std::string WebUsers::getTooltipFilename(
const std::string& username,
2430 const std::string& srcFile,
2431 const std::string& srcFunc,
2432 const std::string& srcId)
2434 std::string filename = (std::string)WEB_LOGIN_DB_PATH + TOOLTIP_DB_PATH +
"/";
2438 mkdir(((std::string)WEB_LOGIN_DB_PATH).c_str(), 0755);
2439 mkdir(((std::string)WEB_LOGIN_DB_PATH + USERS_DB_PATH).c_str(), 0755);
2440 mkdir(filename.c_str(), 0755);
2442 for(
const char& c : username)
2444 (c >=
'a' && c <=
'z') || (c >=
'A' && c <= 'Z') || (c >=
'0' && c <=
'9'))
2449 mkdir(filename.c_str(), 0755);
2451 for(
const char& c : srcFile)
2453 (c >=
'a' && c <=
'z') || (c >=
'A' && c <= 'Z') || (c >=
'0' && c <=
'9'))
2456 for(
const char& c : srcFunc)
2458 (c >=
'a' && c <=
'z') || (c >=
'A' && c <= 'Z') || (c >=
'0' && c <=
'9'))
2461 for(
const char& c : srcId)
2463 (c >=
'a' && c <=
'z') || (c >=
'A' && c <= 'Z') || (c >=
'0' && c <=
'9'))
2470 std::string ots::WebUsers::getUserEmailFromFingerprint(
const std::string& fingerprint)
2472 std::ifstream f(WEB_LOGIN_CERTDATA_PATH);
2479 certFingerprints_[email] = fp;
2481 remove(WEB_LOGIN_CERTDATA_PATH.c_str());
2484 for(
auto fp : certFingerprints_)
2486 if(fp.second == fingerprint)
2495 void WebUsers::tooltipSetNeverShowForUsername(
const std::string& username,
2497 const std::string& srcFile,
2498 const std::string& srcFunc,
2499 const std::string& srcId,
2501 bool temporarySilence)
2503 __COUT__ <<
"Setting tooltip never show for user '" << username <<
"' to "
2504 << doNeverShow <<
" (temporarySilence=" << temporarySilence <<
")" << __E__;
2506 std::string filename = getTooltipFilename(username, srcFile, srcFunc, srcId);
2507 FILE* fp = fopen(filename.c_str(),
"w");
2510 if(temporarySilence)
2513 time(0) + 7 * 24 * 60 * 60);
2514 else if(doNeverShow && username == WebUsers::DEFAULT_ADMIN_USERNAME)
2517 fprintf(fp,
"%ld", time(0) + 30 * 24 * 60 * 60);
2519 __COUT__ <<
"User '" << username
2520 <<
"' may be a shared account, so max silence duration for tooltips "
2521 "is 30 days. Silencing now."
2525 fputc(doNeverShow ?
'1' :
'0', fp);
2529 __COUT_ERR__ <<
"Big problem with tooltips! File not accessible: " << filename
2540 void WebUsers::tooltipCheckForUsername(
const std::string& username,
2542 const std::string& srcFile,
2543 const std::string& srcFunc,
2544 const std::string& srcId)
2546 if(srcId ==
"ALWAYS")
2549 xmldoc->addTextElementToData(
"ShowTooltip",
"1");
2560 std::string silencefilename =
2561 getTooltipFilename(username, SILENCE_ALL_TOOLTIPS_FILENAME,
"",
"");
2563 FILE* silencefp = fopen(silencefilename.c_str(),
"r");
2564 if(silencefp != NULL)
2566 xmldoc->addTextElementToData(
"ShowTooltip",
"0");
2567 tooltipSetNeverShowForUsername(
2568 username, xmldoc, srcFile, srcFunc, srcId,
true,
true);
2572 std::string filename = getTooltipFilename(username, srcFile, srcFunc, srcId);
2573 FILE* fp = fopen(filename.c_str(),
"r");
2578 fgets(line, 100, fp);
2580 sscanf(line,
"%ld", &val);
2583 __COUT__ <<
"tooltip value read = " << val <<
" vs time(0)=" << time(0) << __E__;
2587 xmldoc->addTextElementToData(
"ShowTooltip",
2588 val == 1 ?
"0" : (time(0) > val ?
"1" :
"0"));
2592 xmldoc->addTextElementToData(
"ShowTooltip",
"1");
2599 void WebUsers::resetAllUserTooltips(
const std::string& userNeedle)
2602 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + TOOLTIP_DB_PATH +
"/" + userNeedle)
2604 __COUT__ <<
"Successfully reset Tooltips for user " << userNeedle << __E__;
2610 void WebUsers::silenceAllUserTooltips(
const std::string& username)
2612 std::string silencefilename = getTooltipFilename(
2613 username, SILENCE_ALL_TOOLTIPS_FILENAME,
"",
"");
2614 FILE* silencefp = fopen(silencefilename.c_str(),
"w");
2615 if(silencefp != NULL)
2617 fputs(
"mute tool tips", silencefp);
2643 void WebUsers::insertSettingsForUser(uint64_t uid,
2645 bool includeAccounts)
2647 std::map<std::string , WebUsers::permissionLevel_t> permissionMap =
2648 getPermissionsForUser(uid);
2650 __COUTV__(StringMacros::mapToString(permissionMap));
2651 if(isInactiveForGroup(permissionMap))
2654 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2655 __COUT__ <<
"Gettings settings for user: " << UsersUsernameVector[userIndex] << __E__;
2658 (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_PREFERENCES_PATH +
2659 UsersUsernameVector[userIndex] +
"." + (std::string)USERS_PREFERENCES_FILETYPE;
2663 __COUT__ <<
"Preferences file: " << fn << __E__;
2665 if(!prefXml.loadXmlDocument(fn))
2667 __COUT__ <<
"Preferences are defaults." << __E__;
2669 xmldoc->addTextElementToData(PREF_XML_BGCOLOR_FIELD, PREF_XML_BGCOLOR_DEFAULT);
2670 xmldoc->addTextElementToData(PREF_XML_DBCOLOR_FIELD, PREF_XML_DBCOLOR_DEFAULT);
2671 xmldoc->addTextElementToData(PREF_XML_WINCOLOR_FIELD, PREF_XML_WINCOLOR_DEFAULT);
2672 xmldoc->addTextElementToData(PREF_XML_LAYOUT_FIELD, PREF_XML_LAYOUT_DEFAULT);
2676 __COUT__ <<
"Saved Preferences found." << __E__;
2677 xmldoc->copyDataChildren(prefXml);
2681 if(includeAccounts && isAdminForGroup(permissionMap))
2683 __COUT__ <<
"Admin on our hands" << __E__;
2685 xmldoc->addTextElementToData(PREF_XML_ACCOUNTS_FIELD,
"");
2688 for(uint64_t i = 0; i < UsersUsernameVector.size(); ++i)
2690 xmldoc->addTextElementToParent(
2691 "username", UsersUsernameVector[i], PREF_XML_ACCOUNTS_FIELD);
2692 xmldoc->addTextElementToParent(
2693 "display_name", UsersDisplayNameVector[i], PREF_XML_ACCOUNTS_FIELD);
2695 if(UsersUserEmailVector.size() > i)
2697 xmldoc->addTextElementToParent(
2698 "useremail", UsersUserEmailVector[i], PREF_XML_ACCOUNTS_FIELD);
2702 xmldoc->addTextElementToParent(
"useremail",
"", PREF_XML_ACCOUNTS_FIELD);
2705 xmldoc->addTextElementToParent(
2707 StringMacros::mapToString(UsersPermissionsVector[i]),
2708 PREF_XML_ACCOUNTS_FIELD);
2711 if(UsersSaltVector[i] ==
2713 sprintf(nacStr,
"%d",
int(UsersAccountCreatedTimeVector[i] & 0xffff));
2716 xmldoc->addTextElementToParent(
"nac", nacStr, PREF_XML_ACCOUNTS_FIELD);
2721 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_PREFERENCES_PATH +
2722 (std::string)SYSTEM_PREFERENCES_PREFIX +
"." +
2723 (std::string)USERS_PREFERENCES_FILETYPE;
2724 if(!prefXml.loadXmlDocument(fn))
2726 __COUT__ <<
"System Preferences are defaults." << __E__;
2728 xmldoc->addTextElementToData(PREF_XML_SYSLAYOUT_FIELD,
2729 PREF_XML_SYSLAYOUT_DEFAULT);
2733 __COUT__ <<
"Saved System Preferences found." << __E__;
2734 xmldoc->copyDataChildren(prefXml);
2737 __COUTV__(StringMacros::mapToString(permissionMap));
2740 xmldoc->addTextElementToData(PREF_XML_PERMISSIONS_FIELD,
2741 StringMacros::mapToString(permissionMap));
2744 xmldoc->addTextElementToData(PREF_XML_USERLOCK_FIELD, usersUsernameWithLock_);
2747 xmldoc->addTextElementToData(PREF_XML_USERNAME_FIELD, getUsersUsername(uid));
2750 xmldoc->addTextElementToData(PREF_XML_OTS_OWNER_FIELD, WebUsers::OTS_OWNER);
2757 void WebUsers::setGenericPreference(uint64_t uid,
2758 const std::string& preferenceName,
2759 const std::string& preferenceValue)
2761 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2766 std::string safePreferenceName =
"";
2767 for(
const auto& c : preferenceName)
2768 if((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') || (c >=
'0' && c <=
'9') ||
2769 (c >=
'-' || c <=
'_'))
2770 safePreferenceName += c;
2772 std::string dir = (std::string)WEB_LOGIN_DB_PATH +
2773 (std::string)USERS_PREFERENCES_PATH +
"generic_" +
2774 safePreferenceName +
"/";
2777 mkdir(dir.c_str(), 0755);
2779 std::string fn = UsersUsernameVector[userIndex] +
"_" + safePreferenceName +
"." +
2780 (std::string)USERS_PREFERENCES_FILETYPE;
2782 __COUT__ <<
"Preferences file: " << (dir + fn) << __E__;
2784 FILE* fp = fopen((dir + fn).c_str(),
"w");
2787 fprintf(fp,
"%s", preferenceValue.c_str());
2791 __COUT_ERR__ <<
"Preferences file could not be opened for writing!" << __E__;
2798 std::string WebUsers::getGenericPreference(uint64_t uid,
2799 const std::string& preferenceName,
2802 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2807 std::string safePreferenceName =
"";
2808 for(
const auto& c : preferenceName)
2809 if((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') || (c >=
'0' && c <=
'9') ||
2810 (c >=
'-' || c <=
'_'))
2811 safePreferenceName += c;
2813 std::string dir = (std::string)WEB_LOGIN_DB_PATH +
2814 (std::string)USERS_PREFERENCES_PATH +
"generic_" +
2815 safePreferenceName +
"/";
2817 std::string fn = UsersUsernameVector[userIndex] +
"_" + safePreferenceName +
"." +
2818 (std::string)USERS_PREFERENCES_FILETYPE;
2820 __COUT__ <<
"Preferences file: " << (dir + fn) << __E__;
2823 FILE* fp = fopen((dir + fn).c_str(),
"rb");
2826 fseek(fp, 0, SEEK_END);
2827 long size = ftell(fp);
2829 line.reserve(size + 1);
2831 fgets(&line[0], size + 1, fp);
2834 __COUT__ <<
"Read value " << line << __E__;
2836 xmldoc->addTextElementToData(safePreferenceName, line);
2840 __COUT__ <<
"Using default value." << __E__;
2844 xmldoc->addTextElementToData(safePreferenceName,
"");
2850 void WebUsers::changeSettingsForUser(uint64_t uid,
2851 const std::string& bgcolor,
2852 const std::string& dbcolor,
2853 const std::string& wincolor,
2854 const std::string& layout,
2855 const std::string& syslayout)
2857 std::map<std::string , WebUsers::permissionLevel_t> permissionMap =
2858 getPermissionsForUser(uid);
2859 if(isInactiveForGroup(permissionMap))
2862 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2863 __COUT__ <<
"Changing settings for user: " << UsersUsernameVector[userIndex] << __E__;
2866 (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_PREFERENCES_PATH +
2867 UsersUsernameVector[userIndex] +
"." + (std::string)USERS_PREFERENCES_FILETYPE;
2869 __COUT__ <<
"Preferences file: " << fn << __E__;
2872 prefXml.addTextElementToData(PREF_XML_BGCOLOR_FIELD, bgcolor);
2873 prefXml.addTextElementToData(PREF_XML_DBCOLOR_FIELD, dbcolor);
2874 prefXml.addTextElementToData(PREF_XML_WINCOLOR_FIELD, wincolor);
2875 prefXml.addTextElementToData(PREF_XML_LAYOUT_FIELD, layout);
2877 prefXml.saveXmlDocument(fn);
2880 if(!isAdminForGroup(permissionMap))
2884 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_PREFERENCES_PATH +
2885 (std::string)SYSTEM_PREFERENCES_PREFIX +
"." +
2886 (std::string)USERS_PREFERENCES_FILETYPE;
2889 sysPrefXml.addTextElementToData(PREF_XML_SYSLAYOUT_FIELD, syslayout);
2891 sysPrefXml.saveXmlDocument(fn);
2899 bool WebUsers::setUserWithLock(uint64_t actingUid,
bool lock, const std::
string& username)
2901 std::map<std::string , WebUsers::permissionLevel_t> permissionMap =
2902 getPermissionsForUser(actingUid);
2904 std::string actingUser = getUsersUsername(actingUid);
2906 __COUTV__(actingUser);
2907 __COUT__ <<
"Permissions: " << StringMacros::mapToString(permissionMap) << __E__;
2908 __COUTV__(usersUsernameWithLock_);
2910 __COUTV__(username);
2911 __COUTV__(isUsernameActive(username));
2913 if(lock && (isUsernameActive(username) ||
2914 !CareAboutCookieCodes_))
2916 if(!CareAboutCookieCodes_ &&
2917 username != DEFAULT_ADMIN_USERNAME)
2922 <<
"' tried to lock for a user other than admin in wiz mode. Not allowed."
2926 else if(!isAdminForGroup(permissionMap) &&
2927 actingUser != username)
2929 __MCOUT_ERR__(
"A non-admin user '"
2931 <<
"' tried to lock for a user other than self. Not allowed."
2935 usersUsernameWithLock_ = username;
2937 else if(!lock && usersUsernameWithLock_ == username)
2938 usersUsernameWithLock_ =
"";
2941 if(!isUsernameActive(username))
2942 __MCOUT_ERR__(
"User '" << username <<
"' is inactive." << __E__);
2943 __MCOUT_ERR__(
"Failed to lock for user '" << username <<
".'" << __E__);
2947 __MCOUT_INFO__(
"User '" << username <<
"' has locked out the system!" << __E__);
2951 std::string securityFileName = USER_WITH_LOCK_FILE;
2952 FILE* fp = fopen(securityFileName.c_str(),
"w");
2955 __COUT_INFO__ <<
"USER_WITH_LOCK_FILE " << USER_WITH_LOCK_FILE
2956 <<
" not found. Ignoring." << __E__;
2960 fprintf(fp,
"%s", usersUsernameWithLock_.c_str());
2969 void WebUsers::modifyAccountSettings(uint64_t actingUid,
2971 const std::string& username,
2972 const std::string& displayname,
2973 const std::string& email,
2974 const std::string& permissions)
2976 std::map<std::string , WebUsers::permissionLevel_t> permissionMap =
2977 getPermissionsForUser(actingUid);
2978 if(!isAdminForGroup(permissionMap))
2980 __MCOUT_ERR__(
"Only admins can modify user settings." << __E__);
2984 uint64_t modi = searchUsersDatabaseForUsername(username);
2987 __MCOUT_ERR__(
"Cannot modify first user" << __E__);
2991 if(username.length() < USERNAME_LENGTH || displayname.length() < DISPLAY_NAME_LENGTH)
2993 __MCOUT_ERR__(
"Invalid Username or Display Name must be length "
2994 << USERNAME_LENGTH <<
" or " << DISPLAY_NAME_LENGTH << __E__);
2998 __COUT__ <<
"Input Permissions: " << permissions << __E__;
2999 std::map<std::string , WebUsers::permissionLevel_t> newPermissionsMap;
3003 case MOD_TYPE_UPDATE:
3005 __COUT__ <<
"MOD_TYPE_UPDATE " << username <<
" := " << permissions << __E__;
3007 if(modi == NOT_FOUND_IN_DATABASE)
3009 __COUT__ <<
"User not found!? Should not happen." << __E__;
3013 UsersDisplayNameVector[modi] = displayname;
3014 UsersUserEmailVector[modi] = email;
3016 StringMacros::getMapFromString(permissions, newPermissionsMap);
3020 if(isInactiveForGroup(UsersPermissionsVector[modi]) &&
3021 !isInactiveForGroup(newPermissionsMap))
3023 UsersLoginFailureCountVector[modi] = 0;
3024 UsersSaltVector[modi] =
"";
3026 UsersPermissionsVector[modi] = newPermissionsMap;
3030 uint64_t i = searchUsersDatabaseForUserId(actingUid);
3031 if(i == NOT_FOUND_IN_DATABASE)
3033 __COUT__ <<
"Master User not found!? Should not happen." << __E__;
3036 UsersLastModifierUsernameVector[modi] = UsersUsernameVector[i];
3037 UsersLastModifiedTimeVector[modi] = time(0);
3041 __COUT__ <<
"MOD_TYPE_ADD " << username <<
" - " << displayname << __E__;
3042 createNewAccount(username, displayname, email);
3044 case MOD_TYPE_DELETE:
3045 __COUT__ <<
"MOD_TYPE_DELETE " << username <<
" - " << displayname << __E__;
3046 deleteAccount(username, displayname);
3049 __COUT__ <<
"Undefined command - do nothing " << username << __E__;
3052 saveDatabaseToFile(DB_USERS);
3057 std::string WebUsers::getActiveUsersString()
3059 std::string ret =
"";
3062 for(uint64_t i = 0; i < ActiveSessionUserIdVector.size(); ++i)
3066 for(uint64_t j = 0; j < i; ++j)
3067 if(ActiveSessionUserIdVector[i] == ActiveSessionUserIdVector[j])
3073 if(!repeat && (u = searchUsersDatabaseForUserId(ActiveSessionUserIdVector[i])) !=
3074 NOT_FOUND_IN_DATABASE)
3075 ret += UsersDisplayNameVector[u] +
",";
3077 if(ret.length() > 1)
3078 ret.erase(ret.length() - 1);
3084 uint64_t WebUsers::getAdminUserID()
3086 uint64_t uid = searchUsersDatabaseForUsername(DEFAULT_ADMIN_USERNAME);
3093 void WebUsers::loadUserWithLock()
3095 char username[300] =
"";
3097 std::string securityFileName = USER_WITH_LOCK_FILE;
3098 FILE* fp = fopen(securityFileName.c_str(),
"r");
3101 __COUT_INFO__ <<
"USER_WITH_LOCK_FILE " << USER_WITH_LOCK_FILE
3102 <<
" not found. Defaulting to admin lock." << __E__;
3105 sprintf(username,
"%s", DEFAULT_ADMIN_USERNAME.c_str());
3109 fgets(username, 300, fp);
3116 __COUT__ <<
"Attempting to load username with lock: " << username << __E__;
3118 if(strlen(username) == 0)
3120 __COUT_INFO__ <<
"Loaded state for user-with-lock is unlocked." << __E__;
3124 uint64_t i = searchUsersDatabaseForUsername(username);
3125 if(i == NOT_FOUND_IN_DATABASE)
3127 __COUT_INFO__ <<
"username " << username <<
" not found in database. Ignoring."
3131 __COUT__ <<
"Setting lock" << __E__;
3132 setUserWithLock(UsersUserIdVector[i],
true, username);
3138 std::string WebUsers::getSecurity() {
return securityType_; }
3142 void WebUsers::loadSecuritySelection()
3144 std::string securityFileName = SECURITY_FILE_NAME;
3145 FILE* fp = fopen(securityFileName.c_str(),
"r");
3146 char line[100] =
"";
3148 fgets(line, 100, fp);
3152 while(i < strlen(line) && line[i] >=
'A' && line[i] <=
'z')
3156 if(strcmp(line, SECURITY_TYPE_NONE.c_str()) == 0 ||
3157 strcmp(line, SECURITY_TYPE_DIGEST_ACCESS.c_str()) == 0)
3158 securityType_ = line;
3160 securityType_ = SECURITY_TYPE_NONE;
3162 __COUT__ <<
"The current security type is " << securityType_ << __E__;
3167 if(securityType_ == SECURITY_TYPE_NONE)
3168 CareAboutCookieCodes_ =
false;
3170 CareAboutCookieCodes_ =
true;
3172 __COUT__ <<
"CareAboutCookieCodes_: " << CareAboutCookieCodes_ << __E__;
3176 void WebUsers::NACDisplayThread(
const std::string& nac,
const std::string& user)
3178 INIT_MF(
"WebUsers_NAC");
3187 std::this_thread::sleep_for(std::chrono::seconds(2));
3189 <<
"\n******************************************************************** "
3192 <<
"\n******************************************************************** "
3194 __COUT__ <<
"\n\nNew account code = " << nac <<
" for user: " << user <<
"\n"
3197 <<
"\n******************************************************************** "
3200 <<
"\n******************************************************************** "
3206 void WebUsers::deleteUserData()
3210 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + HASHES_DB_PATH +
"/*").c_str());
3212 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + USERS_DB_PATH +
"/*").c_str());
3214 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + USERS_LOGIN_HISTORY_PATH +
"/*")
3217 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + USERS_PREFERENCES_PATH +
"/*")
3219 std::system((
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + TOOLTIP_DB_PATH).c_str());
3221 std::string serviceDataPath = __ENV__(
"SERVICE_DATA_PATH");
3223 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/MacroData/").c_str());
3224 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/MacroHistory/").c_str());
3225 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/MacroExport/").c_str());
3229 (
"rm -rf " + std::string(serviceDataPath) +
"/ConsolePreferences/").c_str());
3232 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/CodeEditorData/").c_str());
3235 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/OtsWizardData/").c_str());
3238 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/ProgressBarData/").c_str());
3241 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/RunNumber/").c_str());
3242 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/RunControlData/").c_str());
3245 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/VisualizerData/").c_str());
3252 std::system((
"rm -rf " + std::string(__ENV__(
"LOGBOOK_DATA_PATH")) +
"/").c_str());
3254 std::cout << __COUT_HDR_FL__
3255 <<
"$$$$$$$$$$$$$$ Successfully deleted ALL service user data $$$$$$$$$$$$"