1 #include "otsdaq-core/WebUsersUtilities/WebUsers.h"
2 #include "otsdaq-core/XmlUtilities/HttpXmlDocument.h"
4 #include <openssl/sha.h>
17 #define WEB_LOGIN_BKUP_DB_PATH "bkup/"
19 #define SECURITY_FILE_NAME \
20 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 HASHES_DB_GLOBAL_STRING "hashData"
36 #define HASHES_DB_ENTRY_STRING "hashEntry"
37 #define USERS_DB_GLOBAL_STRING "userData"
38 #define USERS_DB_ENTRY_STRING "userEntry"
39 #define USERS_DB_NEXT_UID_STRING "nextUserId"
42 #define PREF_XML_BGCOLOR_FIELD "pref_bgcolor" // -background color
43 #define PREF_XML_DBCOLOR_FIELD "pref_dbcolor" // -dashboard color
44 #define PREF_XML_WINCOLOR_FIELD "pref_wincolor" // -window color
45 #define PREF_XML_LAYOUT_FIELD "pref_layout" // -3 defaults window layouts(and current)
46 #define PREF_XML_SYSLAYOUT_FIELD "pref_syslayout" // -2 defaults window layouts
47 #define PREF_XML_PERMISSIONS_FIELD \
48 "desktop_user_permissions" // 0-255 permissions value (255 is admin super user)
49 #define PREF_XML_USERLOCK_FIELD \
50 "username_with_lock" // user with lock (to lockout others)
51 #define PREF_XML_USERNAME_FIELD "pref_username" // user with lock (to lockout others)
53 #define PREF_XML_BGCOLOR_DEFAULT "rgb(0,76,151)" // -background color
54 #define PREF_XML_DBCOLOR_DEFAULT "rgb(0,40,85)" // -dashboard color
55 #define PREF_XML_WINCOLOR_DEFAULT "rgba(196,229,255,0.9)" // -window color
56 #define PREF_XML_LAYOUT_DEFAULT "0;0;0;0" // 3 default window layouts(and current)
57 #define PREF_XML_SYSLAYOUT_DEFAULT "0;0" // 2 system default window layouts
59 #define PREF_XML_ACCOUNTS_FIELD "users_accounts" // user accounts field for super users
60 #define PREF_XML_LOGIN_HISTORY_FIELD \
61 "login_entry" // login history field for user login history data
63 const std::string WebUsers::DEFAULT_ADMIN_USERNAME =
"admin";
64 const std::string WebUsers::DEFAULT_ADMIN_DISPLAY_NAME =
"Administrator";
65 const std::string WebUsers::DEFAULT_ADMIN_EMAIL =
"root@otsdaq.fnal.gov";
66 const std::string WebUsers::DEFAULT_ITERATOR_USERNAME =
"iterator";
67 const std::string WebUsers::DEFAULT_STATECHANGER_USERNAME =
"statechanger";
68 const std::string WebUsers::DEFAULT_USER_GROUP =
"allUsers";
70 const std::string WebUsers::REQ_NO_LOGIN_RESPONSE =
"NoLogin";
71 const std::string WebUsers::REQ_NO_PERMISSION_RESPONSE =
"NoPermission";
72 const std::string WebUsers::REQ_USER_LOCKOUT_RESPONSE =
"UserLockout";
73 const std::string WebUsers::REQ_LOCK_REQUIRED_RESPONSE =
"LockRequired";
74 const std::string WebUsers::REQ_ALLOW_NO_USER =
"AllowNoUser";
76 const std::string WebUsers::SECURITY_TYPE_NONE =
"NoSecurity";
77 const std::string WebUsers::SECURITY_TYPE_DIGEST_ACCESS =
"DigestAccessAuthentication";
80 #define __MF_SUBJECT__ "WebUsers"
87 usersUsernameWithLock_ =
"";
90 HashesDatabaseEntryFields.push_back(
"hash");
91 HashesDatabaseEntryFields.push_back(
94 UsersDatabaseEntryFields.push_back(
"username");
95 UsersDatabaseEntryFields.push_back(
"displayName");
96 UsersDatabaseEntryFields.push_back(
"salt");
97 UsersDatabaseEntryFields.push_back(
"uid");
98 UsersDatabaseEntryFields.push_back(
"permissions");
99 UsersDatabaseEntryFields.push_back(
"lastLoginAttemptTime");
100 UsersDatabaseEntryFields.push_back(
"accountCreatedTime");
101 UsersDatabaseEntryFields.push_back(
"loginFailureCount");
102 UsersDatabaseEntryFields.push_back(
"lastModifiedTime");
103 UsersDatabaseEntryFields.push_back(
"lastModifierUsername");
104 UsersDatabaseEntryFields.push_back(
"useremail");
107 mkdir(((std::string)WEB_LOGIN_DB_PATH).c_str(), 0755);
108 mkdir(((std::string)WEB_LOGIN_DB_PATH +
"bkup/" + USERS_DB_PATH).c_str(), 0755);
109 mkdir(((std::string)WEB_LOGIN_DB_PATH + HASHES_DB_PATH).c_str(), 0755);
110 mkdir(((std::string)WEB_LOGIN_DB_PATH + USERS_DB_PATH).c_str(), 0755);
111 mkdir(((std::string)WEB_LOGIN_DB_PATH + USERS_LOGIN_HISTORY_PATH).c_str(), 0755);
112 mkdir(((std::string)WEB_LOGIN_DB_PATH + USERS_PREFERENCES_PATH).c_str(), 0755);
115 __COUT__ <<
"FATAL USER DATABASE ERROR - failed to load!!!" << __E__;
117 loadSecuritySelection();
121 std::string user = DEFAULT_ADMIN_USERNAME;
122 if((i = searchUsersDatabaseForUsername(user)) == NOT_FOUND_IN_DATABASE)
124 __SS__ <<
"user: " << user <<
" is not found" << __E__;
125 __COUT_ERR__ << ss.str();
129 else if(UsersSaltVector[i] ==
131 securityType_ == SECURITY_TYPE_DIGEST_ACCESS)
133 char charTimeStr[10];
134 sprintf(charTimeStr,
"%d",
int(UsersAccountCreatedTimeVector[i] & 0xffff));
135 std::string tmpTimeStr = charTimeStr;
141 [](
const std::string& nac,
const std::string& user) {
142 WebUsers::NACDisplayThread(nac, user);
150 loadActiveSessions();
158 __COUT__ <<
"Done with Web Users initialization!" << __E__;
353 bool WebUsers::xmlRequestOnGateway(cgicc::Cgicc& cgi,
354 std::ostringstream* out,
359 WebUsers::initializeRequestUserInfo(cgi, userInfo);
363 if(!cookieCodeIsActiveForRequest(userInfo.cookieCode_,
364 &userInfo.groupPermissionLevelMap_,
367 !userInfo.automatedCommand_ ,
368 &userInfo.usernameWithLock_,
369 &userInfo.activeUserSessionIndex_))
371 *out << userInfo.cookieCode_;
372 goto HANDLE_ACCESS_FAILURE;
376 userInfo.getGroupPermissionLevel();
377 userInfo.username_ = UsersUsernameVector[userInfo.uid_];
378 userInfo.displayName_ = UsersDisplayNameVector[userInfo.uid_];
380 if(!WebUsers::checkRequestAccess(cgi, out, xmldoc, userInfo))
381 goto HANDLE_ACCESS_FAILURE;
385 HANDLE_ACCESS_FAILURE:
387 if(!userInfo.automatedCommand_)
388 __COUT_ERR__ <<
"Failed request (requestType = " << userInfo.requestType_
389 <<
"): " << out->str() << __E__;
397 void WebUsers::initializeRequestUserInfo(cgicc::Cgicc& cgi,
400 userInfo.ip_ = cgi.getEnvironment().getRemoteAddr();
403 userInfo.username_ =
"";
404 userInfo.displayName_ =
"";
405 userInfo.usernameWithLock_ =
"";
406 userInfo.activeUserSessionIndex_ = -1;
407 userInfo.setGroupPermissionLevels(
"");
417 bool WebUsers::checkRequestAccess(cgicc::Cgicc& cgi,
418 std::ostringstream* out,
427 if(!userInfo.automatedCommand_)
429 __COUT__ <<
"requestType ==========>>> " << userInfo.requestType_ << __E__;
430 __COUTV__((
unsigned int)userInfo.permissionLevel_);
431 __COUTV__((
unsigned int)userInfo.permissionsThreshold_);
435 if(!isWizardMode && !userInfo.allowNoUser_ &&
436 userInfo.cookieCode_.length() != WebUsers::COOKIE_CODE_LENGTH)
438 __COUT__ <<
"User (@" << userInfo.ip_
439 <<
") has invalid cookie code: " << userInfo.cookieCode_ << std::endl;
440 *out << WebUsers::REQ_NO_LOGIN_RESPONSE;
444 if(!userInfo.allowNoUser_ &&
445 (userInfo.permissionLevel_ == 0 ||
446 userInfo.permissionLevel_ < userInfo.permissionsThreshold_))
448 *out << WebUsers::REQ_NO_PERMISSION_RESPONSE;
449 __COUT__ <<
"User (@" << userInfo.ip_
450 <<
") has insufficient permissions for requestType '"
451 << userInfo.requestType_
452 <<
"' : " << (
unsigned int)userInfo.permissionLevel_ <<
"<"
453 << (
unsigned int)userInfo.permissionsThreshold_ << std::endl;
460 userInfo.username_ =
"admin";
461 userInfo.displayName_ =
"Admin";
462 userInfo.usernameWithLock_ =
"admin";
463 userInfo.activeUserSessionIndex_ = 0;
470 if(userInfo.allowNoUser_)
471 xmldoc->setHeader(WebUsers::REQ_ALLOW_NO_USER);
473 xmldoc->setHeader(userInfo.cookieCode_);
476 if(userInfo.allowNoUser_)
478 if(userInfo.automatedCommand_)
479 __COUT__ <<
"Allowing anonymous access." << __E__;
490 if((userInfo.checkLock_ || userInfo.requireLock_) &&
491 userInfo.usernameWithLock_ !=
"" &&
492 userInfo.usernameWithLock_ != userInfo.username_)
494 *out << WebUsers::REQ_USER_LOCKOUT_RESPONSE;
495 __COUT__ <<
"User '" << userInfo.username_ <<
"' is locked out. '"
496 << userInfo.usernameWithLock_ <<
"' has lock." << std::endl;
500 if(userInfo.requireLock_ && userInfo.usernameWithLock_ != userInfo.username_)
502 *out << WebUsers::REQ_LOCK_REQUIRED_RESPONSE;
503 __COUT__ <<
"User '" << userInfo.username_ <<
"' must have lock to proceed. ('"
504 << userInfo.usernameWithLock_ <<
"' has lock.)" << std::endl;
516 void WebUsers::saveActiveSessions()
520 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_ACTIVE_SESSIONS_FILE;
521 __COUT__ << fn << __E__;
523 FILE* fp = fopen(fn.c_str(),
"w");
526 __COUT_ERR__ <<
"Error! Persistent active sessions could not be saved to file: "
532 fprintf(fp,
"%d\n", version);
533 for(
unsigned int i = 0; i < ActiveSessionCookieCodeVector.size(); ++i)
541 fprintf(fp,
"%s\n", ActiveSessionCookieCodeVector[i].c_str());
542 fprintf(fp,
"%s\n", ActiveSessionIpVector[i].c_str());
543 fprintf(fp,
"%lu\n", ActiveSessionUserIdVector[i]);
544 fprintf(fp,
"%lu\n", ActiveSessionIndex[i]);
545 fprintf(fp,
"%ld\n", ActiveSessionStartTimeVector[i]);
548 __COUT__ <<
"ActiveSessionCookieCodeVector saved with size "
549 << ActiveSessionCookieCodeVector.size() << __E__;
557 void WebUsers::loadActiveSessions()
561 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_ACTIVE_SESSIONS_FILE;
562 __COUT__ << fn << __E__;
563 FILE* fp = fopen(fn.c_str(),
"r");
567 <<
"Persistent active sessions were not found to be loaded at file: " << fn
574 const int LINELEN = 1000;
576 fgets(line, LINELEN, fp);
577 sscanf(line,
"%d", &version);
580 __COUT__ <<
"Extracting active sessions..." << __E__;
583 while(fgets(line, LINELEN, fp))
586 line[strlen(line) - 1] =
'\0';
587 if(strlen(line) != COOKIE_CODE_LENGTH)
589 __COUT__ <<
"Illegal cookie code found: " << line << __E__;
594 ActiveSessionCookieCodeVector.push_back(line);
596 fgets(line, LINELEN, fp);
598 line[strlen(line) - 1] =
'\0';
599 ActiveSessionIpVector.push_back(line);
601 fgets(line, LINELEN, fp);
602 ActiveSessionUserIdVector.push_back(uint64_t());
605 &(ActiveSessionUserIdVector[ActiveSessionUserIdVector.size() - 1]));
607 fgets(line, LINELEN, fp);
608 ActiveSessionIndex.push_back(uint64_t());
609 sscanf(line,
"%lu", &(ActiveSessionIndex[ActiveSessionIndex.size() - 1]));
611 fgets(line, LINELEN, fp);
612 ActiveSessionStartTimeVector.push_back(time_t());
615 &(ActiveSessionStartTimeVector[ActiveSessionStartTimeVector.size() - 1]));
625 __COUT__ <<
"ActiveSessionCookieCodeVector loaded with size "
626 << ActiveSessionCookieCodeVector.size() << __E__;
630 fp = fopen(fn.c_str(),
"w");
639 bool WebUsers::loadDatabases()
644 const unsigned int LINE_LEN = 1000;
646 unsigned int i, si, c, len, f;
657 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)HASHES_DB_FILE;
658 __COUT__ << fn << __E__;
659 fp = fopen(fn.c_str(),
"r");
662 mkdir(((std::string)WEB_LOGIN_DB_PATH + (std::string)HASHES_DB_PATH).c_str(),
664 __COUT__ << ((std::string)WEB_LOGIN_DB_PATH + (std::string)HASHES_DB_PATH).c_str()
666 fp = fopen(fn.c_str(), "w");
669 __COUT__ << "Hashes database created: " << fn << __E__;
671 saveToDatabase(fp, HASHES_DB_GLOBAL_STRING, "", DB_SAVE_OPEN);
672 saveToDatabase(fp, HASHES_DB_GLOBAL_STRING, "", DB_SAVE_CLOSE);
679 while(fgets(line, LINE_LEN, fp))
681 if(strlen(line) < SHA512_DIGEST_LENGTH)
687 for(i = 0; i < len; ++i)
695 while(i < len && line[i] !=
'<')
706 HashesVector.push_back(&line[si]);
709 sscanf(&line[si],
"%lu", &tmpInt64);
710 HashesAccessTimeVector.push_back(tmpInt64);
714 __COUT__ << HashesAccessTimeVector.size() <<
" Hashes found." << __E__;
728 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_DB_FILE;
729 fp = fopen(fn.c_str(),
"r");
732 mkdir(((std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_DB_PATH).c_str(),
734 __COUT__ << ((std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_DB_PATH).c_str()
736 fp = fopen(fn.c_str(), "w");
739 __COUT__ << "Users database created: " << fn << __E__;
741 saveToDatabase(fp, USERS_DB_GLOBAL_STRING, "", DB_SAVE_OPEN);
743 sprintf(nidStr, "%lu", usersNextUserId_);
744 saveToDatabase(fp, USERS_DB_NEXT_UID_STRING, nidStr, DB_SAVE_OPEN_AND_CLOSE);
745 saveToDatabase(fp, USERS_DB_GLOBAL_STRING, "", DB_SAVE_CLOSE);
748 createNewAccount(DEFAULT_ADMIN_USERNAME,
749 DEFAULT_ADMIN_DISPLAY_NAME,
750 DEFAULT_ADMIN_EMAIL);
757 char salt[] =
"nextUserId";
758 while(fgets(line, LINE_LEN, fp))
760 if(strlen(line) < strlen(salt) * 2)
763 for(i = 0; i < strlen(salt); ++i)
764 if(line[i + 1] != salt[i])
767 if(i == strlen(salt))
772 while(i < LINE_LEN && line[i] !=
'\0' && line[i] !=
'<')
775 sscanf(&line[si],
"%lu", &usersNextUserId_);
780 __COUT__ <<
"Found Users database next user Id: " << usersNextUserId_ << __E__;
784 while(fgets(line, LINE_LEN, fp))
786 if(strlen(line) < 30)
794 __COUT__ <<
"Line buffer too small: " << len << __E__;
800 for(i = 0; i < len; ++i)
804 if(c == 0 || c % 2 == 1)
808 while(i < len && line[i] !=
'<')
818 UsersUsernameVector.push_back(&line[si]);
820 UsersDisplayNameVector.push_back(&line[si]);
822 UsersSaltVector.push_back(&line[si]);
825 sscanf(&line[si],
"%lu", &tmpInt64);
826 UsersUserIdVector.push_back(tmpInt64);
830 UsersPermissionsVector.push_back(
831 std::map<std::string, uint8_t>());
832 std::map<std::string, uint8_t>& lastPermissionsMap =
833 UsersPermissionsVector.back();
834 StringMacros::getMapFromString<uint8_t>(&line[si],
843 if(lastPermissionsMap.find(WebUsers::DEFAULT_USER_GROUP) ==
844 lastPermissionsMap.end())
848 sscanf(&line[si],
"%lu", &tmpInt64);
852 lastPermissionsMap.clear();
854 <<
"User '" << UsersUsernameVector.back()
855 <<
"' is not a member of the default user group '"
856 << WebUsers::DEFAULT_USER_GROUP
857 <<
".' For backward compatibility, permission level "
858 "assumed for default group (permission level := "
859 << tmpInt64 <<
")." << __E__;
860 lastPermissionsMap[WebUsers::DEFAULT_USER_GROUP] =
861 WebUsers::permissionLevel_t(tmpInt64);
867 << UsersUsernameVector.back()
868 <<
"' is not a member of the default user group '"
869 << WebUsers::DEFAULT_USER_GROUP
870 <<
".' Assuming user account is inactive (permission "
872 << WebUsers::PERMISSION_LEVEL_INACTIVE <<
")."
874 lastPermissionsMap[WebUsers::DEFAULT_USER_GROUP] =
875 WebUsers::PERMISSION_LEVEL_INACTIVE;
881 sscanf(&line[si],
"%lu", &tmpInt64);
882 UsersLastLoginAttemptVector.push_back(tmpInt64);
886 sscanf(&line[si],
"%lu", &tmpInt64);
887 UsersAccountCreatedTimeVector.push_back(tmpInt64);
891 sscanf(&line[si],
"%lu", &tmpInt64);
892 UsersLoginFailureCountVector.push_back(tmpInt64);
896 sscanf(&line[si],
"%lu", &tmpInt64);
897 UsersLastModifiedTimeVector.push_back(tmpInt64);
900 UsersLastModifierUsernameVector.push_back(&line[si]);
902 UsersUserEmailVector.push_back(&line[si]);
907 if(f && f != UsersDatabaseEntryFields.size() - 1)
913 <<
"FATAL ERROR - invalid user database found with field number "
923 __COUT__ <<
"Update database to current version - adding fields: "
924 << (UsersDatabaseEntryFields.size() - 1 - f) << __E__;
927 UsersLastModifiedTimeVector.push_back(0);
928 UsersLastModifierUsernameVector.push_back(
"");
932 UsersUserEmailVector.push_back(
"");
939 __COUT__ << UsersLastModifiedTimeVector.size() <<
" Users found." << __E__;
940 for(
size_t ii = 0; ii < UsersLastModifiedTimeVector.size(); ++ii)
942 __COUT__ <<
"User " << UsersUserIdVector[ii]
943 <<
": Name: " << UsersUsernameVector[ii]
944 <<
"\t\tDisplay Name: " << UsersDisplayNameVector[ii]
945 <<
"\t\tEmail: " << UsersUserEmailVector[ii] <<
"\t\tPermissions: "
946 << StringMacros::mapToString(UsersPermissionsVector[ii]) << __E__;
953 void WebUsers::saveToDatabase(FILE* fp,
954 const std::string& field,
955 const std::string& value,
962 std::string newLine = addNewLine ?
"\n" :
"";
964 if(type == DB_SAVE_OPEN_AND_CLOSE)
971 else if(type == DB_SAVE_OPEN)
972 fprintf(fp,
"<%s>%s%s", field.c_str(), value.c_str(), newLine.c_str());
973 else if(type == DB_SAVE_CLOSE)
974 fprintf(fp,
"</%s>%s", field.c_str(), newLine.c_str());
983 bool WebUsers::saveDatabaseToFile(uint8_t db)
985 __COUT__ <<
"Save Database: " << (int)db << __E__;
988 (std::string)WEB_LOGIN_DB_PATH +
989 ((db == DB_USERS) ? (std::string)USERS_DB_FILE : (std::string)HASHES_DB_FILE);
991 __COUT__ <<
"Save Database Filename: " << fn << __E__;
997 sprintf(dayAppend,
".%lu.bkup", time(0) / (3600 * 24));
998 std::string bkup_fn = (std::string)WEB_LOGIN_DB_PATH +
999 (std::string)WEB_LOGIN_BKUP_DB_PATH +
1000 ((db == DB_USERS) ? (std::string)USERS_DB_FILE
1001 : (std::
string)HASHES_DB_FILE) +
1002 (std::
string)dayAppend;
1004 __COUT__ << "Backup file: " << bkup_fn << __E__;
1006 std::
string shell_command = "mv " + fn + " " + bkup_fn;
1007 system(shell_command.c_str());
1010 FILE* fp = fopen(fn.c_str(), "wb");
1018 saveToDatabase(fp, USERS_DB_GLOBAL_STRING,
"", DB_SAVE_OPEN);
1020 sprintf(fldStr,
"%lu", usersNextUserId_);
1021 saveToDatabase(fp, USERS_DB_NEXT_UID_STRING, fldStr, DB_SAVE_OPEN_AND_CLOSE);
1023 __COUT__ <<
"Saving " << UsersUsernameVector.size() <<
" Users." << __E__;
1025 for(uint64_t i = 0; i < UsersUsernameVector.size(); ++i)
1029 saveToDatabase(fp, USERS_DB_ENTRY_STRING,
"", DB_SAVE_OPEN,
false);
1031 for(
unsigned int f = 0; f < UsersDatabaseEntryFields.size(); ++f)
1036 UsersDatabaseEntryFields[f],
1037 UsersUsernameVector[i],
1038 DB_SAVE_OPEN_AND_CLOSE,
1042 UsersDatabaseEntryFields[f],
1043 UsersDisplayNameVector[i],
1044 DB_SAVE_OPEN_AND_CLOSE,
1048 UsersDatabaseEntryFields[f],
1050 DB_SAVE_OPEN_AND_CLOSE,
1054 sprintf(fldStr,
"%lu", UsersUserIdVector[i]);
1056 UsersDatabaseEntryFields[f],
1058 DB_SAVE_OPEN_AND_CLOSE,
1063 UsersDatabaseEntryFields[f],
1064 StringMacros::mapToString(UsersPermissionsVector[i],
1067 DB_SAVE_OPEN_AND_CLOSE,
1071 sprintf(fldStr,
"%lu", UsersLastLoginAttemptVector[i]);
1073 UsersDatabaseEntryFields[f],
1075 DB_SAVE_OPEN_AND_CLOSE,
1080 sprintf(fldStr,
"%lu", UsersAccountCreatedTimeVector[i]);
1082 UsersDatabaseEntryFields[f],
1084 DB_SAVE_OPEN_AND_CLOSE,
1089 sprintf(fldStr,
"%d", UsersLoginFailureCountVector[i]);
1091 UsersDatabaseEntryFields[f],
1093 DB_SAVE_OPEN_AND_CLOSE,
1098 sprintf(fldStr,
"%lu", UsersLastModifiedTimeVector[i]);
1100 UsersDatabaseEntryFields[f],
1102 DB_SAVE_OPEN_AND_CLOSE,
1107 UsersDatabaseEntryFields[f],
1108 UsersLastModifierUsernameVector[i],
1109 DB_SAVE_OPEN_AND_CLOSE,
1113 UsersDatabaseEntryFields[f],
1114 UsersUserEmailVector[i],
1115 DB_SAVE_OPEN_AND_CLOSE,
1119 saveToDatabase(fp, USERS_DB_ENTRY_STRING,
"", DB_SAVE_CLOSE);
1122 saveToDatabase(fp, USERS_DB_GLOBAL_STRING,
"", DB_SAVE_CLOSE);
1126 saveToDatabase(fp, HASHES_DB_GLOBAL_STRING,
"", DB_SAVE_OPEN);
1128 __COUT__ <<
"Saving " << HashesVector.size() <<
" Hashes." << __E__;
1129 for(uint64_t i = 0; i < HashesVector.size(); ++i)
1131 __COUT__ <<
"Saving " << HashesVector[i] <<
" Hashes." << __E__;
1132 saveToDatabase(fp, HASHES_DB_ENTRY_STRING,
"", DB_SAVE_OPEN,
false);
1133 for(
unsigned int f = 0; f < HashesDatabaseEntryFields.size(); ++f)
1137 HashesDatabaseEntryFields[f],
1139 DB_SAVE_OPEN_AND_CLOSE,
1143 sprintf(fldStr,
"%lu", HashesAccessTimeVector[i]);
1145 HashesDatabaseEntryFields[f],
1147 DB_SAVE_OPEN_AND_CLOSE,
1151 saveToDatabase(fp, HASHES_DB_ENTRY_STRING,
"", DB_SAVE_CLOSE);
1154 saveToDatabase(fp, HASHES_DB_GLOBAL_STRING,
"", DB_SAVE_CLOSE);
1168 bool WebUsers::createNewAccount(
const std::string& username,
1169 const std::string& displayName,
1170 const std::string& email)
1172 __COUT__ <<
"Creating account: " << username << __E__;
1175 if((i = searchUsersDatabaseForUsername(username)) != NOT_FOUND_IN_DATABASE ||
1176 username == WebUsers::DEFAULT_ITERATOR_USERNAME ||
1177 username == WebUsers::DEFAULT_STATECHANGER_USERNAME)
1180 __COUT_ERR__ <<
"Username '" << username <<
"' already exists" << __E__;
1185 UsersUsernameVector.push_back(username);
1186 UsersDisplayNameVector.push_back(displayName);
1187 UsersUserEmailVector.push_back(email);
1188 UsersSaltVector.push_back(
"");
1189 std::map<std::string , WebUsers::permissionLevel_t> initPermissions = {
1190 {WebUsers::DEFAULT_USER_GROUP,
1191 (UsersPermissionsVector.size() ? WebUsers::PERMISSION_LEVEL_NOVICE
1192 : WebUsers::PERMISSION_LEVEL_ADMIN)}};
1193 UsersPermissionsVector.push_back(initPermissions);
1195 UsersUserIdVector.push_back(usersNextUserId_++);
1196 if(usersNextUserId_ == (uint64_t)-1)
1198 __COUT__ <<
"usersNextUserId_ wrap around!! Too many users??? Notify Admins."
1200 usersNextUserId_ = 1;
1203 UsersLastLoginAttemptVector.push_back(0);
1204 UsersLoginFailureCountVector.push_back(0);
1205 UsersAccountCreatedTimeVector.push_back(time(0));
1206 UsersLastModifiedTimeVector.push_back(0);
1207 UsersLastModifierUsernameVector.push_back(
"");
1209 return saveDatabaseToFile(DB_USERS);
1218 bool WebUsers::deleteAccount(
const std::string& username,
const std::string& displayName)
1220 uint64_t i = searchUsersDatabaseForUsername(username);
1221 if(i == NOT_FOUND_IN_DATABASE)
1223 if(UsersDisplayNameVector[i] != displayName)
1228 UsersUsernameVector.erase(UsersUsernameVector.begin() + i);
1229 UsersUserEmailVector.erase(UsersUserEmailVector.begin() + i);
1230 UsersDisplayNameVector.erase(UsersDisplayNameVector.begin() + i);
1231 UsersSaltVector.erase(UsersSaltVector.begin() + i);
1232 UsersPermissionsVector.erase(UsersPermissionsVector.begin() + i);
1233 UsersUserIdVector.erase(UsersUserIdVector.begin() + i);
1234 UsersLastLoginAttemptVector.erase(UsersLastLoginAttemptVector.begin() + i);
1235 UsersAccountCreatedTimeVector.erase(UsersAccountCreatedTimeVector.begin() + i);
1236 UsersLoginFailureCountVector.erase(UsersLoginFailureCountVector.begin() + i);
1237 UsersLastModifierUsernameVector.erase(UsersLastModifierUsernameVector.begin() + i);
1238 UsersLastModifiedTimeVector.erase(UsersLastModifiedTimeVector.begin() + i);
1241 return saveDatabaseToFile(DB_USERS);
1245 unsigned int WebUsers::hexByteStrToInt(
const char* h)
1248 char hs[3] = {h[0], h[1],
'\0'};
1249 sscanf(hs,
"%X", &rv);
1254 void WebUsers::intToHexStr(
unsigned char i,
char* h) { sprintf(h,
"%2.2X", i); }
1266 uint64_t WebUsers::attemptActiveSession(
const std::string& uuid,
1267 std::string& jumbledUser,
1268 const std::string& jumbledPw,
1269 std::string& newAccountCode,
1270 const std::string& ip)
1273 if(!checkIpAccess(ip))
1275 __COUT_ERR__ <<
"rejected ip: " << ip << __E__;
1276 return NOT_FOUND_IN_DATABASE;
1279 cleanupExpiredEntries();
1281 if(!CareAboutCookieCodes_)
1283 uint64_t uid = getAdminUserID();
1284 jumbledUser = getUsersDisplayName(uid);
1285 newAccountCode = genCookieCode();
1292 if((i = searchLoginSessionDatabaseForUUID(uuid)) == NOT_FOUND_IN_DATABASE)
1294 __COUT_ERR__ <<
"uuid: " << uuid <<
" is not found" << __E__;
1295 newAccountCode =
"1";
1297 incrementIpBlacklistCount(ip);
1299 return NOT_FOUND_IN_DATABASE;
1301 ++LoginSessionAttemptsVector[i];
1303 std::string user = dejumble(jumbledUser, LoginSessionIdVector[i]);
1305 std::string pw = dejumble(jumbledPw, LoginSessionIdVector[i]);
1308 if((i = searchUsersDatabaseForUsername(user)) == NOT_FOUND_IN_DATABASE)
1310 __COUT_ERR__ <<
"user: " << user <<
" is not found" << __E__;
1312 incrementIpBlacklistCount(ip);
1314 return NOT_FOUND_IN_DATABASE;
1317 ipBlacklistCounts_[ip] = 0;
1319 UsersLastLoginAttemptVector[i] = time(0);
1321 if(isInactiveForGroup(UsersPermissionsVector[i]))
1323 __MCOUT_ERR__(
"User '" << user
1324 <<
"' account INACTIVE (could be due to failed logins)"
1326 return NOT_FOUND_IN_DATABASE;
1329 if(UsersSaltVector[i] ==
"")
1331 __MCOUT__(
"First login attempt for user: " << user << __E__);
1333 char charTimeStr[10];
1334 sprintf(charTimeStr,
"%d",
int(UsersAccountCreatedTimeVector[i] & 0xffff));
1335 std::string tmpTimeStr = charTimeStr;
1336 if(newAccountCode != tmpTimeStr)
1338 __COUT__ <<
"New account code did not match: " << tmpTimeStr
1339 <<
" != " << newAccountCode << __E__;
1340 saveDatabaseToFile(DB_USERS);
1341 return NOT_FOUND_IN_DATABASE;
1347 while(!addToHashesDatabase(
1348 sha512(user, pw, UsersSaltVector[i])))
1353 UsersSaltVector[i] =
"";
1356 __COUT__ <<
"\tHash added: " << HashesVector[HashesVector.size() - 1] << __E__;
1360 std::string salt = UsersSaltVector[i];
1362 if(searchHashesDatabaseForHash(sha512(user, pw, salt)) == NOT_FOUND_IN_DATABASE)
1364 __COUT__ <<
"Failed login for " << user <<
" with permissions "
1365 << StringMacros::mapToString(UsersPermissionsVector[i]) << __E__;
1367 ++UsersLoginFailureCountVector[i];
1368 if(UsersLoginFailureCountVector[i] >= USERS_MAX_LOGIN_FAILURES)
1369 UsersPermissionsVector[i][WebUsers::DEFAULT_USER_GROUP] =
1370 WebUsers::PERMISSION_LEVEL_INACTIVE;
1372 __COUT_INFO__ <<
"User/pw for user '" << user
1373 <<
"' was not correct (Failed Attempt #"
1374 << (int)UsersLoginFailureCountVector[i] <<
" of "
1375 << (
int)USERS_MAX_LOGIN_FAILURES << ")." << __E__;
1377 __COUTV__(isInactiveForGroup(UsersPermissionsVector[i]));
1378 if(isInactiveForGroup(UsersPermissionsVector[i]))
1379 __MCOUT_INFO__("Account '"
1381 << "' has been marked inactive due to too many failed "
1382 "login attempts (Failed Attempt
#"
1383 << (int)UsersLoginFailureCountVector[i]
1384 <<
")! Note only admins can reactivate accounts."
1387 saveDatabaseToFile(DB_USERS);
1388 return NOT_FOUND_IN_DATABASE;
1392 __MCOUT_INFO__(
"Login successful for: " << user << __E__);
1394 UsersLoginFailureCountVector[i] = 0;
1397 for(
int h = 0; h < 2; ++h)
1399 std::string fn = (std::string)WEB_LOGIN_DB_PATH +
1400 (std::string)USERS_LOGIN_HISTORY_PATH +
1401 (h ? USERS_GLOBAL_HISTORY_FILE : UsersUsernameVector[i]) +
"." +
1402 (std::string)USERS_LOGIN_HISTORY_FILETYPE;
1406 if(histXml.loadXmlDocument(fn))
1408 while(histXml.getChildrenCount() + 1 >
1409 (h ? USERS_GLOBAL_HISTORY_SIZE : USERS_LOGIN_HISTORY_SIZE))
1410 histXml.removeDataElement();
1413 __COUT__ <<
"No previous login history found." << __E__;
1419 "Time=%lu Username=%s Permissions=%s UID=%lu",
1421 UsersUsernameVector[i].c_str(),
1422 StringMacros::mapToString(UsersPermissionsVector[i]).c_str(),
1423 UsersUserIdVector[i]);
1426 "Time=%lu displayName=%s Permissions=%s UID=%lu",
1428 UsersDisplayNameVector[i].c_str(),
1429 StringMacros::mapToString(UsersPermissionsVector[i]).c_str(),
1430 UsersUserIdVector[i]);
1431 histXml.addTextElementToData(PREF_XML_LOGIN_HISTORY_FIELD, entryStr);
1434 histXml.saveXmlDocument(fn);
1438 saveDatabaseToFile(DB_USERS);
1439 jumbledUser = UsersDisplayNameVector[i];
1440 newAccountCode = createNewActiveSession(UsersUserIdVector[i],
1442 return UsersUserIdVector[i];
1451 uint64_t WebUsers::attemptActiveSessionWithCert(
const std::string& uuid,
1453 std::string& cookieCode,
1455 const std::string& ip)
1457 if(!checkIpAccess(ip))
1459 __COUT_ERR__ <<
"rejected ip: " << ip << __E__;
1460 return NOT_FOUND_IN_DATABASE;
1463 cleanupExpiredEntries();
1465 if(!CareAboutCookieCodes_)
1467 uint64_t uid = getAdminUserID();
1468 email = getUsersDisplayName(uid);
1469 cookieCode = genCookieCode();
1475 __COUT__ <<
"Rejecting logon with blank fingerprint" << __E__;
1477 incrementIpBlacklistCount(ip);
1479 return NOT_FOUND_IN_DATABASE;
1485 if((i = searchLoginSessionDatabaseForUUID(uuid)) == NOT_FOUND_IN_DATABASE)
1487 __COUT__ <<
"uuid: " << uuid <<
" is not found" << __E__;
1490 incrementIpBlacklistCount(ip);
1492 return NOT_FOUND_IN_DATABASE;
1494 ++LoginSessionAttemptsVector[i];
1496 email = getUserEmailFromFingerprint(email);
1497 __COUT__ <<
"DejumbledEmail = " << email << __E__;
1500 __COUT__ <<
"Rejecting logon with unknown fingerprint" << __E__;
1502 incrementIpBlacklistCount(ip);
1504 return NOT_FOUND_IN_DATABASE;
1508 if((i = searchUsersDatabaseForUserEmail(email)) == NOT_FOUND_IN_DATABASE)
1510 __COUT__ <<
"email: " << email <<
" is not found" << __E__;
1512 incrementIpBlacklistCount(ip);
1514 return NOT_FOUND_IN_DATABASE;
1517 ipBlacklistCounts_[ip] = 0;
1519 user = getUsersUsername(i);
1521 UsersLastLoginAttemptVector[i] = time(0);
1522 if(isInactiveForGroup(UsersPermissionsVector[i]))
1524 __MCOUT__(
"User '" << user
1525 <<
"' account INACTIVE (could be due to failed logins)."
1527 return NOT_FOUND_IN_DATABASE;
1530 if(UsersSaltVector[i] ==
"")
1532 return NOT_FOUND_IN_DATABASE;
1535 __MCOUT__(
"Login successful for: " << user << __E__);
1537 UsersLoginFailureCountVector[i] = 0;
1540 for(
int h = 0; h < 2; ++h)
1542 std::string fn = (std::string)WEB_LOGIN_DB_PATH +
1543 (std::string)USERS_LOGIN_HISTORY_PATH +
1544 (h ? USERS_GLOBAL_HISTORY_FILE : UsersUsernameVector[i]) +
"." +
1545 (std::string)USERS_LOGIN_HISTORY_FILETYPE;
1549 if(histXml.loadXmlDocument(fn))
1551 while(histXml.getChildrenCount() + 1 >
1552 (h ? USERS_GLOBAL_HISTORY_SIZE : USERS_LOGIN_HISTORY_SIZE))
1553 histXml.removeDataElement();
1556 __COUT__ <<
"No previous login history found." << __E__;
1562 "Time=%lu Username=%s Permissions=%s UID=%lu",
1564 UsersUsernameVector[i].c_str(),
1565 StringMacros::mapToString(UsersPermissionsVector[i]).c_str(),
1566 UsersUserIdVector[i]);
1569 "Time=%lu displayName=%s Permissions=%s UID=%lu",
1571 UsersDisplayNameVector[i].c_str(),
1572 StringMacros::mapToString(UsersPermissionsVector[i]).c_str(),
1573 UsersUserIdVector[i]);
1574 histXml.addTextElementToData(PREF_XML_LOGIN_HISTORY_FIELD, entryStr);
1577 histXml.saveXmlDocument(fn);
1581 saveDatabaseToFile(DB_USERS);
1582 email = UsersDisplayNameVector[i];
1583 cookieCode = createNewActiveSession(UsersUserIdVector[i],
1585 return UsersUserIdVector[i];
1591 uint64_t WebUsers::searchActiveSessionDatabaseForCookie(
1592 const std::string& cookieCode)
const
1595 for(; i < ActiveSessionCookieCodeVector.size(); ++i)
1596 if(ActiveSessionCookieCodeVector[i] == cookieCode)
1598 return (i == ActiveSessionCookieCodeVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1604 bool WebUsers::isUsernameActive(
const std::string& username)
const
1607 if((u = searchUsersDatabaseForUsername(username)) == NOT_FOUND_IN_DATABASE)
1609 return isUserIdActive(UsersUserIdVector[u]);
1615 bool WebUsers::isUserIdActive(uint64_t uid)
const
1618 for(; i < ActiveSessionUserIdVector.size(); ++i)
1619 if(ActiveSessionUserIdVector[i] == uid)
1627 uint64_t WebUsers::searchUsersDatabaseForUsername(
const std::string& username)
const
1630 for(; i < UsersUsernameVector.size(); ++i)
1631 if(UsersUsernameVector[i] == username)
1633 return (i == UsersUsernameVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1639 uint64_t WebUsers::searchUsersDatabaseForUserEmail(
const std::string& useremail)
const
1642 for(; i < UsersUserEmailVector.size(); ++i)
1643 if(UsersUserEmailVector[i] == useremail)
1645 return (i == UsersUserEmailVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1651 uint64_t WebUsers::searchUsersDatabaseForUserId(uint64_t uid)
const
1654 for(; i < UsersUserIdVector.size(); ++i)
1655 if(UsersUserIdVector[i] == uid)
1657 return (i == UsersUserIdVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1663 uint64_t WebUsers::searchLoginSessionDatabaseForUUID(
const std::string& uuid)
const
1666 for(; i < LoginSessionUUIDVector.size(); ++i)
1667 if(LoginSessionUUIDVector[i] == uuid)
1669 return (i == LoginSessionUUIDVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1675 uint64_t WebUsers::searchHashesDatabaseForHash(
const std::string& hash)
1680 for(; i < HashesVector.size(); ++i)
1681 if(HashesVector[i] == hash)
1686 if(i < HashesAccessTimeVector
1688 HashesAccessTimeVector.push_back(
1689 (time(0) + (rand() % 2 ? 1 : -1) * (rand() % 30 * 24 * 60 * 60)) &
1690 0x0FFFFFFFFFE000000);
1693 return (i == HashesVector.size()) ? NOT_FOUND_IN_DATABASE : i;
1700 bool WebUsers::addToHashesDatabase(
const std::string& hash)
1702 if(searchHashesDatabaseForHash(hash) != NOT_FOUND_IN_DATABASE)
1704 __COUT__ <<
"Hash collision: " << hash << __E__;
1707 HashesVector.push_back(hash);
1708 HashesAccessTimeVector.push_back(
1709 (time(0) + (rand() % 2 ? 1 : -1) * (rand() % 30 * 24 * 60 * 60)) &
1710 0x0FFFFFFFFFE000000);
1713 return saveDatabaseToFile(DB_HASHES);
1718 std::string WebUsers::genCookieCode()
1721 std::string cc =
"";
1722 for(uint32_t i = 0; i < COOKIE_CODE_LENGTH / 2; ++i)
1724 intToHexStr(rand(), hexStr);
1732 void WebUsers::removeLoginSessionEntry(
unsigned int i)
1734 LoginSessionIdVector.erase(LoginSessionIdVector.begin() + i);
1735 LoginSessionUUIDVector.erase(LoginSessionUUIDVector.begin() + i);
1736 LoginSessionIpVector.erase(LoginSessionIpVector.begin() + i);
1737 LoginSessionStartTimeVector.erase(LoginSessionStartTimeVector.begin() + i);
1738 LoginSessionAttemptsVector.erase(LoginSessionAttemptsVector.begin() + i);
1745 std::string WebUsers::createNewActiveSession(uint64_t uid,
1746 const std::string& ip,
1750 ActiveSessionCookieCodeVector.push_back(genCookieCode());
1751 ActiveSessionIpVector.push_back(ip);
1752 ActiveSessionUserIdVector.push_back(uid);
1753 ActiveSessionStartTimeVector.push_back(time(0));
1756 ActiveSessionIndex.push_back(asIndex);
1761 for(uint64_t j = 0; j < ActiveSessionIndex.size(); ++j)
1762 if(ActiveSessionUserIdVector[j] == uid &&
1763 max < ActiveSessionIndex[j])
1764 max = ActiveSessionIndex[j];
1766 ActiveSessionIndex.push_back(max ? max + 1 : 1);
1769 return ActiveSessionCookieCodeVector[ActiveSessionCookieCodeVector.size() - 1];
1774 void WebUsers::removeActiveSessionEntry(
unsigned int i)
1776 ActiveSessionCookieCodeVector.erase(ActiveSessionCookieCodeVector.begin() + i);
1777 ActiveSessionIpVector.erase(ActiveSessionIpVector.begin() + i);
1778 ActiveSessionUserIdVector.erase(ActiveSessionUserIdVector.begin() + i);
1779 ActiveSessionStartTimeVector.erase(ActiveSessionStartTimeVector.begin() + i);
1780 ActiveSessionIndex.erase(ActiveSessionIndex.begin() + i);
1807 std::string WebUsers::refreshCookieCode(
unsigned int i,
bool enableRefresh)
1810 for(uint64_t j = ActiveSessionUserIdVector.size() - 1; j != (uint64_t)-1;
1812 if(ActiveSessionUserIdVector[j] == ActiveSessionUserIdVector[i] &&
1813 ActiveSessionIndex[j] ==
1814 ActiveSessionIndex[i])
1819 if(enableRefresh && (time(0) - ActiveSessionStartTimeVector[j] >
1820 ACTIVE_SESSION_EXPIRATION_TIME / 2))
1824 ActiveSessionStartTimeVector[j] =
1825 time(0) - ACTIVE_SESSION_EXPIRATION_TIME +
1826 ACTIVE_SESSION_COOKIE_OVERLAP_TIME;
1832 return createNewActiveSession(ActiveSessionUserIdVector[i],
1833 ActiveSessionIpVector[i],
1834 ActiveSessionIndex[i]);
1837 return ActiveSessionCookieCodeVector[j];
1848 uint64_t WebUsers::isCookieCodeActiveForLogin(
const std::string& uuid,
1849 std::string& cookieCode,
1850 std::string& username)
1852 if(!CareAboutCookieCodes_)
1853 return getAdminUserID();
1859 if(!ActiveSessionStartTimeVector.size())
1860 return NOT_FOUND_IN_DATABASE;
1865 if((i = searchLoginSessionDatabaseForUUID(uuid)) == NOT_FOUND_IN_DATABASE)
1867 __COUT__ <<
"uuid not found: " << uuid << __E__;
1868 return NOT_FOUND_IN_DATABASE;
1872 dejumble(username, LoginSessionIdVector[i]);
1875 if((i = searchActiveSessionDatabaseForCookie(cookieCode)) == NOT_FOUND_IN_DATABASE)
1877 __COUT__ <<
"Cookie code not found" << __E__;
1878 return NOT_FOUND_IN_DATABASE;
1882 if((j = searchUsersDatabaseForUserId(ActiveSessionUserIdVector[i])) ==
1883 NOT_FOUND_IN_DATABASE)
1885 __COUT__ <<
"User ID not found" << __E__;
1886 return NOT_FOUND_IN_DATABASE;
1890 if(UsersUsernameVector[j] != username)
1892 __COUT__ <<
"cookieCode: " << cookieCode <<
" was.." << __E__;
1893 __COUT__ <<
"username: " << username <<
" is not found" << __E__;
1894 return NOT_FOUND_IN_DATABASE;
1897 username = UsersDisplayNameVector[j];
1898 cookieCode = refreshCookieCode(i);
1899 return UsersUserIdVector[j];
1905 uint64_t WebUsers::getActiveSessionCountForUser(uint64_t uid)
1908 std::vector<uint64_t> uniqueAsi;
1911 for(i = 0; i < ActiveSessionUserIdVector.size(); ++i)
1912 if(ActiveSessionUserIdVector[i] == uid)
1917 for(j = 0; j < uniqueAsi.size(); ++j)
1918 if(uniqueAsi[j] == ActiveSessionIndex[i])
1925 uniqueAsi.push_back(ActiveSessionIndex[i]);
1928 __COUT__ <<
"Found " << uniqueAsi.size() <<
" active sessions for uid " << uid
1931 return uniqueAsi.size();
1940 bool WebUsers::checkIpAccess(
const std::string& ip)
1945 FILE* fp = fopen((IP_ACCEPT_FILE).c_str(),
"r");
1951 while(fgets(line, 300, fp))
1955 if(len > 2 && line[len - 1] ==
'\n')
1956 line[len - 1] =
'\0';
1957 if(StringMacros::wildCardMatch(ip, line))
1964 fp = fopen((IP_REJECT_FILE).c_str(),
"r");
1967 while(fgets(line, 300, fp))
1971 if(len > 2 && line[len - 1] ==
'\n')
1972 line[len - 1] =
'\0';
1973 if(StringMacros::wildCardMatch(ip, line))
1980 fp = fopen((IP_BLACKLIST_FILE).c_str(),
"r");
1983 while(fgets(line, 300, fp))
1987 if(len > 2 && line[len - 1] ==
'\n')
1988 line[len - 1] =
'\0';
1989 if(StringMacros::wildCardMatch(ip, line))
2002 void WebUsers::incrementIpBlacklistCount(
const std::string& ip)
2005 auto it = ipBlacklistCounts_.find(ip);
2006 if(it == ipBlacklistCounts_.end())
2008 __COUT__ <<
"First error for ip '" << ip <<
"'" << __E__;
2009 ipBlacklistCounts_[ip] = 1;
2015 if(it->second >= IP_BLACKLIST_COUNT_THRESHOLD)
2017 __MCOUT__(
"Adding IP '" << ip <<
"' to blacklist!" << __E__);
2020 FILE* fp = fopen((IP_BLACKLIST_FILE).c_str(),
"a");
2023 __SS__ <<
"IP black list file '" << IP_BLACKLIST_FILE
2024 <<
"' could not be opened." << __E__;
2025 __MCOUT_ERR__(ss.str());
2028 fprintf(fp,
"%s\n", ip.c_str());
2036 std::string WebUsers::getUsersDisplayName(uint64_t uid)
2039 if((i = searchUsersDatabaseForUserId(uid)) == NOT_FOUND_IN_DATABASE)
2041 return UsersDisplayNameVector[i];
2046 std::string WebUsers::getUsersUsername(uint64_t uid)
2049 if((i = searchUsersDatabaseForUserId(uid)) == NOT_FOUND_IN_DATABASE)
2051 return UsersUsernameVector[i];
2065 uint64_t WebUsers::cookieCodeLogout(
const std::string& cookieCode,
2066 bool logoutOtherUserSessions,
2068 const std::string& ip)
2073 if((i = searchActiveSessionDatabaseForCookie(cookieCode)) == NOT_FOUND_IN_DATABASE)
2075 __COUT__ <<
"Cookie code not found" << __E__;
2077 incrementIpBlacklistCount(ip);
2079 return NOT_FOUND_IN_DATABASE;
2082 ipBlacklistCounts_[ip] = 0;
2085 if(ActiveSessionIpVector[i] != ip)
2087 __COUT__ <<
"IP does not match active session" << __E__;
2088 return NOT_FOUND_IN_DATABASE;
2097 uint64_t asi = ActiveSessionIndex[i];
2098 uint64_t uid = ActiveSessionUserIdVector[i];
2101 uint64_t logoutCount = 0;
2104 while(i < ActiveSessionIndex.size())
2106 if((logoutOtherUserSessions && ActiveSessionUserIdVector[i] == uid &&
2107 ActiveSessionIndex[i] != asi) ||
2108 (!logoutOtherUserSessions && ActiveSessionUserIdVector[i] == uid &&
2109 ActiveSessionIndex[i] == asi))
2111 __COUT__ <<
"Logging out of active session " << ActiveSessionUserIdVector[i]
2112 <<
"-" << ActiveSessionIndex[i] << __E__;
2113 removeActiveSessionEntry(i);
2120 __COUT__ <<
"Found and removed active session count = " << logoutCount << __E__;
2127 bool WebUsers::getUserInfoForCookie(std::string& cookieCode,
2128 std::string* userName,
2129 std::string* displayName,
2130 uint64_t* activeSessionIndex)
2137 if(!CareAboutCookieCodes_)
2139 uint64_t uid = getAdminUserID();
2141 *userName = getUsersUsername(uid);
2143 *displayName = getUsersDisplayName(uid);
2144 if(activeSessionIndex)
2145 *activeSessionIndex = -1;
2152 if((i = searchActiveSessionDatabaseForCookie(cookieCode)) == NOT_FOUND_IN_DATABASE)
2154 __COUT__ <<
"cookieCode NOT_FOUND_IN_DATABASE" << __E__;
2159 if((j = searchUsersDatabaseForUserId(ActiveSessionUserIdVector[i])) ==
2160 NOT_FOUND_IN_DATABASE)
2162 __COUT__ <<
"ActiveSessionUserIdVector NOT_FOUND_IN_DATABASE" << __E__;
2167 *userName = UsersUsernameVector[j];
2169 *displayName = UsersDisplayNameVector[j];
2170 if(activeSessionIndex)
2171 *activeSessionIndex = ActiveSessionIndex[i];
2188 bool WebUsers::cookieCodeIsActiveForRequest(
2189 std::string& cookieCode,
2190 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>* userPermissions,
2192 const std::string& ip,
2194 std::string* userWithLock,
2195 uint64_t* activeUserSessionIndex)
2200 if(!checkIpAccess(ip))
2202 __COUT_ERR__ <<
"User IP rejected." << __E__;
2203 cookieCode = REQ_NO_LOGIN_RESPONSE;
2207 cleanupExpiredEntries();
2214 if(!CareAboutCookieCodes_)
2218 std::map<std::string , WebUsers::permissionLevel_t>(
2219 {{WebUsers::DEFAULT_USER_GROUP, WebUsers::PERMISSION_LEVEL_ADMIN}});
2221 *uid = getAdminUserID();
2223 *userWithLock = usersUsernameWithLock_;
2224 if(activeUserSessionIndex)
2225 *activeUserSessionIndex = -1;
2227 if(cookieCode.size() != COOKIE_CODE_LENGTH)
2228 cookieCode = genCookieCode();
2235 if((i = searchActiveSessionDatabaseForCookie(cookieCode)) == NOT_FOUND_IN_DATABASE)
2237 __COUT_ERR__ <<
"Cookie code not found" << __E__;
2238 cookieCode = REQ_NO_LOGIN_RESPONSE;
2240 incrementIpBlacklistCount(ip);
2245 ipBlacklistCounts_[ip] = 0;
2248 if(ip !=
"0" && ActiveSessionIpVector[i] != ip)
2250 __COUTV__(ActiveSessionIpVector[i]);
2252 __COUT_ERR__ <<
"IP does not match active session." << __E__;
2253 cookieCode = REQ_NO_LOGIN_RESPONSE;
2258 if((j = searchUsersDatabaseForUserId(ActiveSessionUserIdVector[i])) ==
2259 NOT_FOUND_IN_DATABASE)
2261 __COUT_ERR__ <<
"User ID not found" << __E__;
2262 cookieCode = REQ_NO_LOGIN_RESPONSE;
2266 std::map<std::string , WebUsers::permissionLevel_t> tmpPerm =
2267 getPermissionsForUser(UsersUserIdVector[j]);
2269 if(isInactiveForGroup(tmpPerm))
2271 cookieCode = REQ_NO_PERMISSION_RESPONSE;
2277 *userPermissions = tmpPerm;
2279 *uid = UsersUserIdVector[j];
2281 *userWithLock = usersUsernameWithLock_;
2282 if(activeUserSessionIndex)
2283 *activeUserSessionIndex = ActiveSessionIndex[i];
2285 cookieCode = refreshCookieCode(i, refresh);
2297 void WebUsers::cleanupExpiredEntries(std::vector<std::string>* loggedOutUsernames)
2302 if(loggedOutUsernames)
2304 for(i = 0; i < UsersLoggedOutUsernames_.size(); ++i)
2305 loggedOutUsernames->push_back(UsersLoggedOutUsernames_[i]);
2306 UsersLoggedOutUsernames_.clear();
2310 for(i = 0; i < LoginSessionStartTimeVector.size(); ++i)
2311 if(LoginSessionStartTimeVector[i] + LOGIN_SESSION_EXPIRATION_TIME <
2313 LoginSessionAttemptsVector[i] > LOGIN_SESSION_ATTEMPTS_MAX)
2319 removeLoginSessionEntry(i);
2332 for(i = 0; i < ActiveSessionStartTimeVector.size(); ++i)
2333 if(ActiveSessionStartTimeVector[i] + ACTIVE_SESSION_EXPIRATION_TIME <=
2342 tmpUid = ActiveSessionUserIdVector[i];
2343 removeActiveSessionEntry(i);
2345 if(!isUserIdActive(tmpUid))
2348 if(loggedOutUsernames)
2349 loggedOutUsernames->push_back(
2350 UsersUsernameVector[searchUsersDatabaseForUserId(tmpUid)]);
2352 UsersLoggedOutUsernames_.push_back(
2353 UsersUsernameVector[searchUsersDatabaseForUserId(tmpUid)]);
2374 if(CareAboutCookieCodes_ &&
2375 !isUsernameActive(usersUsernameWithLock_))
2376 usersUsernameWithLock_ =
"";
2386 std::string WebUsers::createNewLoginSession(
const std::string& UUID,
2387 const std::string& ip)
2393 for(; i < LoginSessionUUIDVector.size(); ++i)
2394 if(LoginSessionUUIDVector[i] == UUID)
2397 if(i != LoginSessionUUIDVector.size())
2399 __COUT_ERR__ <<
"UUID: " << UUID <<
" is not unique" << __E__;
2404 LoginSessionUUIDVector.push_back(UUID);
2408 std::string sid =
"";
2409 for(i = 0; i < SESSION_ID_LENGTH / 2; ++i)
2411 intToHexStr(rand(), hexStr);
2414 LoginSessionIdVector.push_back(sid);
2415 LoginSessionIpVector.push_back(ip);
2416 LoginSessionStartTimeVector.push_back(time(0));
2417 LoginSessionAttemptsVector.push_back(0);
2427 std::string WebUsers::sha512(
const std::string& user,
2428 const std::string& password,
2431 SHA512_CTX sha512_context;
2436 SHA512_Init(&sha512_context);
2438 for(
unsigned int i = 0; i < 8; ++i)
2439 sha512_context.h[i] += rand();
2441 for(
unsigned int i = 0; i <
sizeof(SHA512_CTX); ++i)
2443 intToHexStr((uint8_t)(((uint8_t*)(&sha512_context))[i]), hexStr);
2445 salt.append(hexStr);
2453 for(
unsigned int i = 0; i <
sizeof(SHA512_CTX); ++i)
2454 ((uint8_t*)(&sha512_context))[i] = hexByteStrToInt(&(salt.c_str()[i * 2]));
2457 std::string strToHash = salt + user + password;
2460 unsigned char hash[SHA512_DIGEST_LENGTH];
2462 char retHash[SHA512_DIGEST_LENGTH * 2 + 1];
2466 SHA512_Update(&sha512_context, strToHash.c_str(), strToHash.length());
2468 SHA512_Final(hash, &sha512_context);
2472 for(i = 0; i < SHA512_DIGEST_LENGTH; i++)
2473 sprintf(retHash + (i * 2),
"%02x", hash[i]);
2476 retHash[SHA512_DIGEST_LENGTH * 2] =
'\0';
2487 std::string WebUsers::dejumble(
const std::string& u,
const std::string& s)
2489 if(s.length() != SESSION_ID_LENGTH)
2492 const int ss = s.length() / 2;
2493 int p = hexByteStrToInt(&(s.c_str()[0])) % ss;
2494 int n = hexByteStrToInt(&(s.c_str()[p * 2])) % ss;
2495 int len = (hexByteStrToInt(&(u.c_str()[p * 2])) - p - n + ss * 3) % ss;
2497 std::vector<bool> x(ss);
2498 for(
int i = 0; i < ss; ++i)
2502 int c = hexByteStrToInt(&(u.c_str()[p * 2]));
2504 std::string user =
"";
2506 for(
int l = 0; l < len; ++l)
2508 p = (p + hexByteStrToInt(&(s.c_str()[p * 2]))) % ss;
2512 n = hexByteStrToInt(&(s.c_str()[p * 2]));
2513 user.append(1, (hexByteStrToInt(&(u.c_str()[p * 2])) - c - n + ss * 4) % ss);
2514 c = hexByteStrToInt(&(u.c_str()[p * 2]));
2523 std::map<std::string , WebUsers::permissionLevel_t>
2524 WebUsers::getPermissionsForUser(uint64_t uid)
2527 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2529 if(userIndex < UsersPermissionsVector.size())
2530 return UsersPermissionsVector[userIndex];
2533 std::map<std::string , WebUsers::permissionLevel_t> retErrorMap;
2534 retErrorMap[WebUsers::DEFAULT_USER_GROUP] = WebUsers::PERMISSION_LEVEL_INACTIVE;
2539 WebUsers::permissionLevel_t WebUsers::getPermissionLevelForGroup(
2540 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap,
2541 const std::string& groupName)
2543 auto it = permissionMap.find(groupName);
2544 if(it == permissionMap.end())
2546 __COUT__ <<
"Group name '" << groupName
2547 <<
"' not found - assuming inactive user in this group." << __E__;
2548 return WebUsers::PERMISSION_LEVEL_INACTIVE;
2554 bool WebUsers::isInactiveForGroup(
2555 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap,
2556 const std::string& groupName)
2558 return getPermissionLevelForGroup(permissionMap, groupName) ==
2559 WebUsers::PERMISSION_LEVEL_INACTIVE;
2563 bool WebUsers::isAdminForGroup(
2564 std::map<std::string /*groupName*/, WebUsers::permissionLevel_t>& permissionMap,
2565 const std::string& groupName)
2567 return getPermissionLevelForGroup(permissionMap, groupName) ==
2568 WebUsers::PERMISSION_LEVEL_ADMIN;
2574 std::string WebUsers::getTooltipFilename(
const std::string& username,
2575 const std::string& srcFile,
2576 const std::string& srcFunc,
2577 const std::string& srcId)
2579 std::string filename = (std::string)WEB_LOGIN_DB_PATH + TOOLTIP_DB_PATH +
"/";
2583 mkdir(((std::string)WEB_LOGIN_DB_PATH).c_str(), 0755);
2584 mkdir(((std::string)WEB_LOGIN_DB_PATH + USERS_DB_PATH).c_str(), 0755);
2585 mkdir(filename.c_str(), 0755);
2587 for(
const char& c : username)
2589 (c >=
'a' && c <=
'z') || (c >=
'A' && c <= 'Z') || (c >=
'0' && c <=
'9'))
2594 mkdir(filename.c_str(), 0755);
2596 for(
const char& c : srcFile)
2598 (c >=
'a' && c <=
'z') || (c >=
'A' && c <= 'Z') || (c >=
'0' && c <=
'9'))
2601 for(
const char& c : srcFunc)
2603 (c >=
'a' && c <=
'z') || (c >=
'A' && c <= 'Z') || (c >=
'0' && c <=
'9'))
2606 for(
const char& c : srcId)
2608 (c >=
'a' && c <=
'z') || (c >=
'A' && c <= 'Z') || (c >=
'0' && c <=
'9'))
2615 std::string ots::WebUsers::getUserEmailFromFingerprint(
const std::string& fingerprint)
2617 std::ifstream f(WEB_LOGIN_CERTDATA_PATH);
2624 certFingerprints_[email] = fp;
2626 remove(WEB_LOGIN_CERTDATA_PATH.c_str());
2629 for(
auto fp : certFingerprints_)
2631 if(fp.second == fingerprint)
2640 void WebUsers::tooltipSetNeverShowForUsername(
const std::string& username,
2642 const std::string& srcFile,
2643 const std::string& srcFunc,
2644 const std::string& srcId,
2646 bool temporarySilence)
2648 __COUT__ <<
"Setting tooltip never show for user '" << username <<
"' to "
2649 << doNeverShow <<
" (temporarySilence=" << temporarySilence <<
")" << __E__;
2651 std::string filename = getTooltipFilename(username, srcFile, srcFunc, srcId);
2652 FILE* fp = fopen(filename.c_str(),
"w");
2655 if(temporarySilence)
2658 time(0) + 7 * 24 * 60 * 60);
2659 else if(doNeverShow && username == WebUsers::DEFAULT_ADMIN_USERNAME)
2662 fprintf(fp,
"%ld", time(0) + 30 * 24 * 60 * 60);
2664 __COUT__ <<
"User '" << username
2665 <<
"' may be a shared account, so max silence duration for tooltips "
2666 "is 30 days. Silencing now."
2670 fputc(doNeverShow ?
'1' :
'0', fp);
2674 __COUT_ERR__ <<
"Big problem with tooltips! File not accessible: " << filename
2685 void WebUsers::tooltipCheckForUsername(
const std::string& username,
2687 const std::string& srcFile,
2688 const std::string& srcFunc,
2689 const std::string& srcId)
2691 if(srcId ==
"ALWAYS")
2694 xmldoc->addTextElementToData(
"ShowTooltip",
"1");
2704 std::string filename = getTooltipFilename(username, srcFile, srcFunc, srcId);
2705 FILE* fp = fopen(filename.c_str(),
"r");
2710 fgets(line, 100, fp);
2712 sscanf(line,
"%ld", &val);
2715 __COUT__ <<
"tooltip value read = " << val <<
" vs time(0)=" << time(0) << __E__;
2719 xmldoc->addTextElementToData(
"ShowTooltip",
2720 val == 1 ?
"0" : (time(0) > val ?
"1" :
"0"));
2723 xmldoc->addTextElementToData(
"ShowTooltip",
"1");
2728 void WebUsers::resetAllUserTooltips(
const std::string& userNeedle)
2731 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + TOOLTIP_DB_PATH +
"/" + userNeedle)
2733 __COUT__ <<
"Successfully reset Tooltips for user " << userNeedle << __E__;
2756 void WebUsers::insertSettingsForUser(uint64_t uid,
2758 bool includeAccounts)
2760 std::map<std::string , WebUsers::permissionLevel_t> permissionMap =
2761 getPermissionsForUser(uid);
2763 __COUTV__(StringMacros::mapToString(permissionMap));
2764 if(isInactiveForGroup(permissionMap))
2767 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2768 __COUT__ <<
"Gettings settings for user: " << UsersUsernameVector[userIndex] << __E__;
2771 (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_PREFERENCES_PATH +
2772 UsersUsernameVector[userIndex] +
"." + (std::string)USERS_PREFERENCES_FILETYPE;
2776 __COUT__ <<
"Preferences file: " << fn << __E__;
2778 if(!prefXml.loadXmlDocument(fn))
2780 __COUT__ <<
"Preferences are defaults." << __E__;
2782 xmldoc->addTextElementToData(PREF_XML_BGCOLOR_FIELD, PREF_XML_BGCOLOR_DEFAULT);
2783 xmldoc->addTextElementToData(PREF_XML_DBCOLOR_FIELD, PREF_XML_DBCOLOR_DEFAULT);
2784 xmldoc->addTextElementToData(PREF_XML_WINCOLOR_FIELD, PREF_XML_WINCOLOR_DEFAULT);
2785 xmldoc->addTextElementToData(PREF_XML_LAYOUT_FIELD, PREF_XML_LAYOUT_DEFAULT);
2789 __COUT__ <<
"Saved Preferences found." << __E__;
2790 xmldoc->copyDataChildren(prefXml);
2794 if(includeAccounts && isAdminForGroup(permissionMap))
2796 __COUT__ <<
"Admin on our hands" << __E__;
2798 xmldoc->addTextElementToData(PREF_XML_ACCOUNTS_FIELD,
"");
2801 for(uint64_t i = 0; i < UsersUsernameVector.size(); ++i)
2803 xmldoc->addTextElementToParent(
2804 "username", UsersUsernameVector[i], PREF_XML_ACCOUNTS_FIELD);
2805 xmldoc->addTextElementToParent(
2806 "display_name", UsersDisplayNameVector[i], PREF_XML_ACCOUNTS_FIELD);
2808 if(UsersUserEmailVector.size() > i)
2810 xmldoc->addTextElementToParent(
2811 "useremail", UsersUserEmailVector[i], PREF_XML_ACCOUNTS_FIELD);
2815 xmldoc->addTextElementToParent(
"useremail",
"", PREF_XML_ACCOUNTS_FIELD);
2818 xmldoc->addTextElementToParent(
2820 StringMacros::mapToString(UsersPermissionsVector[i]),
2821 PREF_XML_ACCOUNTS_FIELD);
2824 if(UsersSaltVector[i] ==
2826 sprintf(nacStr,
"%d",
int(UsersAccountCreatedTimeVector[i] & 0xffff));
2829 xmldoc->addTextElementToParent(
"nac", nacStr, PREF_XML_ACCOUNTS_FIELD);
2834 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_PREFERENCES_PATH +
2835 (std::string)SYSTEM_PREFERENCES_PREFIX +
"." +
2836 (std::string)USERS_PREFERENCES_FILETYPE;
2837 if(!prefXml.loadXmlDocument(fn))
2839 __COUT__ <<
"System Preferences are defaults." << __E__;
2841 xmldoc->addTextElementToData(PREF_XML_SYSLAYOUT_FIELD,
2842 PREF_XML_SYSLAYOUT_DEFAULT);
2846 __COUT__ <<
"Saved System Preferences found." << __E__;
2847 xmldoc->copyDataChildren(prefXml);
2850 __COUTV__(StringMacros::mapToString(permissionMap));
2853 xmldoc->addTextElementToData(PREF_XML_PERMISSIONS_FIELD,
2854 StringMacros::mapToString(permissionMap));
2857 xmldoc->addTextElementToData(PREF_XML_USERLOCK_FIELD, usersUsernameWithLock_);
2860 xmldoc->addTextElementToData(PREF_XML_USERNAME_FIELD, getUsersUsername(uid));
2867 void WebUsers::setGenericPreference(uint64_t uid,
2868 const std::string& preferenceName,
2869 const std::string& preferenceValue)
2871 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2876 std::string safePreferenceName =
"";
2877 for(
const auto& c : preferenceName)
2878 if((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') || (c >=
'0' && c <=
'9') ||
2879 (c >=
'-' || c <=
'_'))
2880 safePreferenceName += c;
2882 std::string dir = (std::string)WEB_LOGIN_DB_PATH +
2883 (std::string)USERS_PREFERENCES_PATH +
"generic_" +
2884 safePreferenceName +
"/";
2887 mkdir(dir.c_str(), 0755);
2889 std::string fn = UsersUsernameVector[userIndex] +
"_" + safePreferenceName +
"." +
2890 (std::string)USERS_PREFERENCES_FILETYPE;
2892 __COUT__ <<
"Preferences file: " << (dir + fn) << __E__;
2894 FILE* fp = fopen((dir + fn).c_str(),
"w");
2897 fprintf(fp,
"%s", preferenceValue.c_str());
2901 __COUT_ERR__ <<
"Preferences file could not be opened for writing!" << __E__;
2908 std::string WebUsers::getGenericPreference(uint64_t uid,
2909 const std::string& preferenceName,
2912 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2917 std::string safePreferenceName =
"";
2918 for(
const auto& c : preferenceName)
2919 if((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z') || (c >=
'0' && c <=
'9') ||
2920 (c >=
'-' || c <=
'_'))
2921 safePreferenceName += c;
2923 std::string dir = (std::string)WEB_LOGIN_DB_PATH +
2924 (std::string)USERS_PREFERENCES_PATH +
"generic_" +
2925 safePreferenceName +
"/";
2927 std::string fn = UsersUsernameVector[userIndex] +
"_" + safePreferenceName +
"." +
2928 (std::string)USERS_PREFERENCES_FILETYPE;
2930 __COUT__ <<
"Preferences file: " << (dir + fn) << __E__;
2933 FILE* fp = fopen((dir + fn).c_str(),
"rb");
2936 fseek(fp, 0, SEEK_END);
2937 long size = ftell(fp);
2939 line.reserve(size + 1);
2941 fgets(&line[0], size + 1, fp);
2944 __COUT__ <<
"Read value " << line << __E__;
2946 xmldoc->addTextElementToData(safePreferenceName, line);
2950 __COUT__ <<
"Using default value." << __E__;
2954 xmldoc->addTextElementToData(safePreferenceName,
"");
2960 void WebUsers::changeSettingsForUser(uint64_t uid,
2961 const std::string& bgcolor,
2962 const std::string& dbcolor,
2963 const std::string& wincolor,
2964 const std::string& layout,
2965 const std::string& syslayout)
2967 std::map<std::string , WebUsers::permissionLevel_t> permissionMap =
2968 getPermissionsForUser(uid);
2969 if(isInactiveForGroup(permissionMap))
2972 uint64_t userIndex = searchUsersDatabaseForUserId(uid);
2973 __COUT__ <<
"Changing settings for user: " << UsersUsernameVector[userIndex] << __E__;
2976 (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_PREFERENCES_PATH +
2977 UsersUsernameVector[userIndex] +
"." + (std::string)USERS_PREFERENCES_FILETYPE;
2979 __COUT__ <<
"Preferences file: " << fn << __E__;
2982 prefXml.addTextElementToData(PREF_XML_BGCOLOR_FIELD, bgcolor);
2983 prefXml.addTextElementToData(PREF_XML_DBCOLOR_FIELD, dbcolor);
2984 prefXml.addTextElementToData(PREF_XML_WINCOLOR_FIELD, wincolor);
2985 prefXml.addTextElementToData(PREF_XML_LAYOUT_FIELD, layout);
2987 prefXml.saveXmlDocument(fn);
2990 if(!isAdminForGroup(permissionMap))
2994 fn = (std::string)WEB_LOGIN_DB_PATH + (std::string)USERS_PREFERENCES_PATH +
2995 (std::string)SYSTEM_PREFERENCES_PREFIX +
"." +
2996 (std::string)USERS_PREFERENCES_FILETYPE;
2999 sysPrefXml.addTextElementToData(PREF_XML_SYSLAYOUT_FIELD, syslayout);
3001 sysPrefXml.saveXmlDocument(fn);
3009 bool WebUsers::setUserWithLock(uint64_t actingUid,
bool lock, const std::
string& username)
3011 std::map<std::string , WebUsers::permissionLevel_t> permissionMap =
3012 getPermissionsForUser(actingUid);
3014 std::string actingUser = getUsersUsername(actingUid);
3016 __COUTV__(actingUser);
3017 __COUT__ <<
"Permissions: " << StringMacros::mapToString(permissionMap) << __E__;
3018 __COUTV__(usersUsernameWithLock_);
3020 __COUTV__(username);
3021 __COUTV__(isUsernameActive(username));
3023 if(lock && (isUsernameActive(username) ||
3024 !CareAboutCookieCodes_))
3026 if(!CareAboutCookieCodes_ &&
3027 username != DEFAULT_ADMIN_USERNAME)
3032 <<
"' tried to lock for a user other than admin in wiz mode. Not allowed."
3036 else if(!isAdminForGroup(permissionMap) &&
3037 actingUser != username)
3039 __MCOUT_ERR__(
"A non-admin user '"
3041 <<
"' tried to lock for a user other than self. Not allowed."
3045 usersUsernameWithLock_ = username;
3047 else if(!lock && usersUsernameWithLock_ == username)
3048 usersUsernameWithLock_ =
"";
3051 if(!isUsernameActive(username))
3052 __MCOUT_ERR__(
"User '" << username <<
"' is inactive." << __E__);
3053 __MCOUT_ERR__(
"Failed to lock for user '" << username <<
".'" << __E__);
3057 __MCOUT_INFO__(
"User '" << username <<
"' has locked out the system!" << __E__);
3061 std::string securityFileName = USER_WITH_LOCK_FILE;
3062 FILE* fp = fopen(securityFileName.c_str(),
"w");
3065 __COUT_INFO__ <<
"USER_WITH_LOCK_FILE " << USER_WITH_LOCK_FILE
3066 <<
" not found. Ignoring." << __E__;
3070 fprintf(fp,
"%s", usersUsernameWithLock_.c_str());
3079 void WebUsers::modifyAccountSettings(uint64_t actingUid,
3081 const std::string& username,
3082 const std::string& displayname,
3083 const std::string& email,
3084 const std::string& permissions)
3086 std::map<std::string , WebUsers::permissionLevel_t> permissionMap =
3087 getPermissionsForUser(actingUid);
3088 if(!isAdminForGroup(permissionMap))
3090 __MCOUT_ERR__(
"Only admins can modify user settings." << __E__);
3094 uint64_t modi = searchUsersDatabaseForUsername(username);
3097 __MCOUT_ERR__(
"Cannot modify first user" << __E__);
3101 if(username.length() < USERNAME_LENGTH || displayname.length() < DISPLAY_NAME_LENGTH)
3103 __MCOUT_ERR__(
"Invalid Username or Display Name must be length "
3104 << USERNAME_LENGTH <<
" or " << DISPLAY_NAME_LENGTH << __E__);
3108 __COUT__ <<
"Input Permissions: " << permissions << __E__;
3109 std::map<std::string , WebUsers::permissionLevel_t> newPermissionsMap;
3113 case MOD_TYPE_UPDATE:
3115 __COUT__ <<
"MOD_TYPE_UPDATE " << username <<
" := " << permissions << __E__;
3117 if(modi == NOT_FOUND_IN_DATABASE)
3119 __COUT__ <<
"User not found!? Should not happen." << __E__;
3123 UsersDisplayNameVector[modi] = displayname;
3124 UsersUserEmailVector[modi] = email;
3126 StringMacros::getMapFromString(permissions, newPermissionsMap);
3130 if(isInactiveForGroup(UsersPermissionsVector[modi]) &&
3131 !isInactiveForGroup(newPermissionsMap))
3133 UsersLoginFailureCountVector[modi] = 0;
3134 UsersSaltVector[modi] =
"";
3136 UsersPermissionsVector[modi] = newPermissionsMap;
3140 uint64_t i = searchUsersDatabaseForUserId(actingUid);
3141 if(i == NOT_FOUND_IN_DATABASE)
3143 __COUT__ <<
"Master User not found!? Should not happen." << __E__;
3146 UsersLastModifierUsernameVector[modi] = UsersUsernameVector[i];
3147 UsersLastModifiedTimeVector[modi] = time(0);
3151 __COUT__ <<
"MOD_TYPE_ADD " << username <<
" - " << displayname << __E__;
3152 createNewAccount(username, displayname, email);
3154 case MOD_TYPE_DELETE:
3155 __COUT__ <<
"MOD_TYPE_DELETE " << username <<
" - " << displayname << __E__;
3156 deleteAccount(username, displayname);
3159 __COUT__ <<
"Undefined command - do nothing " << username << __E__;
3162 saveDatabaseToFile(DB_USERS);
3167 std::string WebUsers::getActiveUsersString()
3169 std::string ret =
"";
3172 for(uint64_t i = 0; i < ActiveSessionUserIdVector.size(); ++i)
3176 for(uint64_t j = 0; j < i; ++j)
3177 if(ActiveSessionUserIdVector[i] == ActiveSessionUserIdVector[j])
3183 if(!repeat && (u = searchUsersDatabaseForUserId(ActiveSessionUserIdVector[i])) !=
3184 NOT_FOUND_IN_DATABASE)
3185 ret += UsersDisplayNameVector[u] +
",";
3187 if(ret.length() > 1)
3188 ret.erase(ret.length() - 1);
3194 uint64_t WebUsers::getAdminUserID()
3196 uint64_t uid = searchUsersDatabaseForUsername(DEFAULT_ADMIN_USERNAME);
3203 void WebUsers::loadUserWithLock()
3205 char username[300] =
"";
3207 std::string securityFileName = USER_WITH_LOCK_FILE;
3208 FILE* fp = fopen(securityFileName.c_str(),
"r");
3211 __COUT_INFO__ <<
"USER_WITH_LOCK_FILE " << USER_WITH_LOCK_FILE
3212 <<
" not found. Defaulting to admin lock." << __E__;
3215 sprintf(username,
"%s", DEFAULT_ADMIN_USERNAME.c_str());
3219 fgets(username, 300, fp);
3226 __COUT__ <<
"Attempting to load username with lock: " << username << __E__;
3228 if(strlen(username) == 0)
3230 __COUT_INFO__ <<
"Loaded state for user-with-lock is unlocked." << __E__;
3234 uint64_t i = searchUsersDatabaseForUsername(username);
3235 if(i == NOT_FOUND_IN_DATABASE)
3237 __COUT_INFO__ <<
"username " << username <<
" not found in database. Ignoring."
3241 __COUT__ <<
"Setting lock" << __E__;
3242 setUserWithLock(UsersUserIdVector[i],
true, username);
3248 std::string WebUsers::getSecurity() {
return securityType_; }
3252 void WebUsers::loadSecuritySelection()
3254 std::string securityFileName = SECURITY_FILE_NAME;
3255 FILE* fp = fopen(securityFileName.c_str(),
"r");
3256 char line[100] =
"";
3258 fgets(line, 100, fp);
3262 while(i < strlen(line) && line[i] >=
'A' && line[i] <=
'z')
3266 if(strcmp(line, SECURITY_TYPE_NONE.c_str()) == 0 ||
3267 strcmp(line, SECURITY_TYPE_DIGEST_ACCESS.c_str()) == 0)
3268 securityType_ = line;
3270 securityType_ = SECURITY_TYPE_NONE;
3272 __COUT__ <<
"The current security type is " << securityType_ << __E__;
3277 if(securityType_ == SECURITY_TYPE_NONE)
3278 CareAboutCookieCodes_ =
false;
3280 CareAboutCookieCodes_ =
true;
3282 __COUT__ <<
"CareAboutCookieCodes_: " << CareAboutCookieCodes_ << __E__;
3286 void WebUsers::NACDisplayThread(
const std::string& nac,
const std::string& user)
3288 INIT_MF(
"WebUsers_NAC");
3297 std::this_thread::sleep_for(std::chrono::seconds(2));
3299 <<
"\n******************************************************************** "
3302 <<
"\n******************************************************************** "
3304 __COUT__ <<
"\n\nNew account code = " << nac <<
" for user: " << user <<
"\n"
3307 <<
"\n******************************************************************** "
3310 <<
"\n******************************************************************** "
3316 void WebUsers::deleteUserData()
3320 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + HASHES_DB_PATH +
"/*").c_str());
3322 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + USERS_DB_PATH +
"/*").c_str());
3324 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + USERS_LOGIN_HISTORY_PATH +
"/*")
3327 (
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + USERS_PREFERENCES_PATH +
"/*")
3329 std::system((
"rm -rf " + (std::string)WEB_LOGIN_DB_PATH + TOOLTIP_DB_PATH).c_str());
3331 std::string serviceDataPath = __ENV__(
"SERVICE_DATA_PATH");
3333 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/MacroData/").c_str());
3334 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/MacroHistory/").c_str());
3335 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/MacroExport/").c_str());
3339 (
"rm -rf " + std::string(serviceDataPath) +
"/ConsolePreferences/").c_str());
3342 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/CodeEditorData/").c_str());
3345 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/OtsWizardData/").c_str());
3348 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/ProgressBarData/").c_str());
3351 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/RunNumber/").c_str());
3352 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/RunControlData/").c_str());
3355 std::system((
"rm -rf " + std::string(serviceDataPath) +
"/VisualizerData/").c_str());
3362 std::system((
"rm -rf " + std::string(__ENV__(
"LOGBOOK_DATA_PATH")) +
"/").c_str());
3364 std::cout << __COUT_HDR_FL__
3365 <<
"$$$$$$$$$$$$$$ Successfully deleted ALL service user data $$$$$$$$$$$$"