Loading src/session.cpp +240 −210 Changes for src/session.cpp: 240 added lines, 210 removed lines. Original line number Diff line number Diff line Loading @@ -181,28 +181,15 @@ void authdb::SessionData::setGPOResults(const std::vector<std::pair<uuid::uuid, } } authdb::Session::Session() { // ===== LocalSession ===== authdb::LocalSession::LocalSession() { _firstData=nullptr; _lastData=nullptr; } authdb::Session::Session(const Session& src) : Session(){ std::lock_guard<std::mutex> guard(_SessionLock); for(SessionData *cur=src._firstData; cur; cur=cur->_next){ if(!_firstData){ _firstData=new SessionData(cur->_sid,cur->_uid,cur->_did,cur->_members); _lastData=_firstData; }else{ _lastData->_next=new SessionData(cur->_sid,cur->_uid,cur->_did,cur->_members); _lastData=_lastData->_next; } _lastData->_username=cur->_username; } } void authdb::Session::clear(){ void authdb::LocalSession::clear(){ std::lock_guard<std::mutex> guard(_lock); SessionData *del=_firstData; while(del){ SessionData *next=del->_next; Loading @@ -214,78 +201,83 @@ void authdb::Session::clear(){ _lastData=nullptr; } authdb::Session::~Session(){ authdb::LocalSession::~LocalSession(){ clear(); }; const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid::uuid domainid,uuid::uuid userid){ } // --- Cluster deduplication: check if session for this user+domain already exists --- if (g_Cluster && g_Cluster->isRunning()) { // Check local sessions first (same user+domain) { std::lock_guard<std::mutex> guard(_SessionLock); authdb::SessionData *authdb::LocalSession::findLocal(uuid::uuid sessionid){ for(SessionData *cur=_firstData; cur; cur=cur->_next){ uuid::uuid cur_uid, cur_did; cur->getUid(cur_uid); cur->getDid(cur_did); if (cur_uid == userid && cur_did == domainid) { return cur; // Reuse existing local session } if(cur->_sid==sessionid) return cur; } return nullptr; } // Check cluster peers for existing session uuid::uuid cluster_sid; std::vector<uuid::uuid> cluster_members; std::string cluster_username; std::vector<std::pair<uuid::uuid, bool>> cluster_gpo; if (g_Cluster->fetchSession(userid, domainid, cluster_sid, cluster_members, cluster_username, cluster_gpo)) { // Session exists on another node, import it locally SessionData *imported = new SessionData(cluster_sid, userid, domainid, cluster_members); imported->_username = cluster_username; imported->setGPOResults(cluster_gpo); std::lock_guard<std::mutex> guard(_SessionLock); void authdb::LocalSession::appendLocal(SessionData *sess){ if(!_firstData){ _firstData = imported; _firstData=sess; _lastData=_firstData; }else{ _lastData->_next = imported; _lastData->_next=sess; _lastData=_lastData->_next; } return imported; } } else { // No cluster: still deduplicate locally std::lock_guard<std::mutex> guard(_SessionLock); void authdb::LocalSession::removeLocal(uuid::uuid sessionid){ SessionData *prev=nullptr; for(SessionData *cur=_firstData; cur; cur=cur->_next){ uuid::uuid cur_uid, cur_did; cur->getUid(cur_uid); cur->getDid(cur_did); if (cur_uid == userid && cur_did == domainid) { return cur; if(cur->_sid==sessionid){ if(prev) prev->_next=cur->_next; if(cur==_firstData) _firstData=cur->_next; if(cur==_lastData) _lastData=prev; cur->_next=nullptr; delete cur; return; } prev=cur; } } void authdb::LocalSession::cleanupExpired(){ auto now=std::chrono::steady_clock::now(); SessionData *prev=nullptr; SessionData *cur=_firstData; while(cur){ auto age=std::chrono::duration_cast<std::chrono::hours>(now - cur->_created).count(); if(age >= 24){ SessionData *next=cur->_next; if(prev) prev->_next=next; if(cur==_firstData) _firstData=next; if(cur==_lastData) _lastData=prev; cur->_next=nullptr; delete cur; cur=next; }else{ prev=cur; cur=cur->_next; } } } static authdb::SessionData *createSessionData(authdb::AuthBackend &backend, uuid::uuid domainid, uuid::uuid userid){ using namespace authdb; std::string username; std::shared_ptr<authdb::AuthData::Record> cur=std::make_shared<authdb::AuthData::Record>(); std::shared_ptr<AuthData::Record> cur=std::make_shared<AuthData::Record>(); size_t rd=sizeof(authdb::AuthHeader),end=backend.end(); size_t rd=sizeof(AuthHeader),end=backend.end(); while(rd<end){ cur->type=EmptyData; backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if(cur->type == UserData && strcmp(cur->fieldname,"username")==0 && userid==cur->ruid){ unsigned char *tmp = new unsigned char[cur->datasize]; backend.read(tmp,cur->datasize); username=reinterpret_cast<char*>(tmp); Loading @@ -293,20 +285,16 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid } } std::shared_ptr<std::vector<uuid::uuid>> mbs = std::make_shared<std::vector<uuid::uuid>>(); rd=sizeof(authdb::AuthHeader); rd=sizeof(AuthHeader); while(rd<end){ backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if( !uuid::uuid(cur->ruid).empty() && cur->type == GroupData && strcmp(cur->fieldname,"groupname")==0){ Group group; std::shared_ptr<class GroupData> grpi=std::make_shared<class GroupData>(cur->ruid); size_t upos=sizeof(authdb::AuthHeader); size_t upos=sizeof(AuthHeader); group.info(backend,*grpi,upos); if(grpi->isMember(userid)){ mbs->emplace_back(cur->ruid); Loading @@ -319,27 +307,21 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid SessionData *newSession=new SessionData(sid,userid,domainid,*mbs); newSession->_username=username; newSession->_GPOResult.next=nullptr; SessionData::GPOResult *gpores=&newSession->_GPOResult; Gpo gpo; std::vector<uuid::uuid> allow; rd=sizeof(authdb::AuthHeader); rd=sizeof(AuthHeader); while(rd<end){ backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if(cur->type == PolicyData && strcmp(cur->fieldname,"gponame")==0){ std::shared_ptr<class GpoData> gpodat=std::make_shared<class GpoData>(cur->ruid); size_t upos=sizeof(authdb::AuthHeader); size_t upos=sizeof(AuthHeader); gpo.info(backend,*gpodat,upos); if(!gpores->GPOId.empty()){ gpores->next=new SessionData::GPOResult(); Loading Loading @@ -373,42 +355,156 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid } if(!found){ bool defval=(strcmp(gpo_default[i][3],"true")==0); // Add to session result if(!gpores->GPOId.empty()){ gpores->next=new SessionData::GPOResult(); gpores=gpores->next; } gpores->GPOId=defid; gpores->GPORes=defval; // Create the missing GPO record in the backend try { GpoData gdat(defid); gdat.setName(gpo_default[i][1]); gdat.setDesc(gpo_default[i][2]); gdat.setGpoValue(defval); gpo.create(backend, &gdat); } catch (...) { // GPO may already exist from concurrent creation } catch (...) {} } } return newSession; } static void reloadSessionData(authdb::AuthBackend &backend, authdb::SessionData *cursess){ using namespace authdb; Group group; std::string username; cursess->_members.clear(); std::shared_ptr<AuthData::Record> cur=std::make_shared<AuthData::Record>(); size_t rd=sizeof(AuthHeader),end=backend.end(); while(rd<end){ cur->type=EmptyData; backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if(cur->type == UserData && strcmp(cur->fieldname,"username")==0 && uuid::uuid(cur->ruid)==cursess->_uid.value){ const std::shared_ptr<unsigned char[]>tmp(new unsigned char[cur->datasize]); backend.read(tmp.get(),cur->datasize); username=reinterpret_cast<char*>(tmp.get()); } if(cur->type == GroupData && strcmp(cur->fieldname,"groupname")==0){ std::shared_ptr<class GroupData> grpi=std::make_shared<class GroupData>(cur->ruid); size_t upos=sizeof(AuthHeader); group.info(backend,*grpi,upos); if(grpi->isMember(cursess->_uid.value)) cursess->_members.emplace_back(cur->ruid); } } cursess->_username=username; } const authdb::SessionData *authdb::LocalSession::addSession(AuthBackend &backend,uuid::uuid domainid,uuid::uuid userid){ { std::lock_guard<std::mutex> guard(_SessionLock); std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); for (SessionData *cur = _firstData; cur; cur = cur->_next) { uuid::uuid cur_uid, cur_did; cur->getUid(cur_uid); cur->getDid(cur_did); if (cur_uid == userid && cur_did == domainid) return cur; } } SessionData *newSession = createSessionData(backend, domainid, userid); std::lock_guard<std::mutex> guard(_lock); appendLocal(newSession); return newSession; } const authdb::SessionData *authdb::LocalSession::getSession(uuid::uuid sessionid){ std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); return findLocal(sessionid); } if(!_firstData){ _firstData=newSession; _lastData=_firstData; }else{ _lastData->_next=newSession; _lastData=_lastData->_next; void authdb::LocalSession::remSession(uuid::uuid sessionid){ std::lock_guard<std::mutex> guard(_lock); removeLocal(sessionid); } void authdb::LocalSession::relSession(AuthBackend &backend,uuid::uuid sessionid){ std::lock_guard<std::mutex> guard(_lock); SessionData *cursess = findLocal(sessionid); if(!cursess) throw AuthBackendError("reload session: sessionid not found !"); reloadSessionData(backend, cursess); } void authdb::LocalSession::listSessions(std::vector<SessionInfo> &out){ std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); out.clear(); for(SessionData *cur=_firstData; cur; cur=cur->_next){ SessionInfo info; cur->getSid(info.sid); cur->getUid(info.uid); cur->getDid(info.did); info.username = cur->getUsername(); out.push_back(std::move(info)); } } // ===== ClusterSession ===== authdb::ClusterSession::ClusterSession() : LocalSession() {} authdb::ClusterSession::~ClusterSession() {} const authdb::SessionData *authdb::ClusterSession::addSession(AuthBackend &backend,uuid::uuid domainid,uuid::uuid userid){ // Check local cache first { std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); for (SessionData *cur = _firstData; cur; cur = cur->_next) { uuid::uuid cur_uid, cur_did; cur->getUid(cur_uid); cur->getDid(cur_did); if (cur_uid == userid && cur_did == domainid) return cur; } } // Check cluster for existing session if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid cluster_sid; std::vector<uuid::uuid> cluster_members; std::string cluster_username; std::vector<std::pair<uuid::uuid, bool>> cluster_gpo; if (g_Cluster->fetchSession(userid, domainid, cluster_sid, cluster_members, cluster_username, cluster_gpo)) { SessionData *imported = new SessionData(cluster_sid, userid, domainid, cluster_members); imported->_username = cluster_username; imported->setGPOResults(cluster_gpo); std::lock_guard<std::mutex> guard(_lock); appendLocal(imported); return imported; } } // Create new session SessionData *newSession = createSessionData(backend, domainid, userid); { std::lock_guard<std::mutex> guard(_lock); appendLocal(newSession); } // Push to cluster for replication if (g_Cluster && g_Cluster->isRunning()) { g_Cluster->pushSession(*newSession); Loading @@ -417,12 +513,12 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid return newSession; } const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ const authdb::SessionData *authdb::ClusterSession::getSession(uuid::uuid sessionid){ { std::lock_guard<std::mutex> guard(_SessionLock); std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); for(SessionData *cur=_firstData; cur; cur=cur->_next){ if(cur->_sid==sessionid){ SessionData *cur = findLocal(sessionid); if (cur) { // Sync with cluster session_store_ (local memory only, no network) if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid c_sid, c_uid, c_did; Loading @@ -431,31 +527,20 @@ const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ std::vector<std::pair<uuid::uuid, bool>> c_gpo; if (g_Cluster->fetchSessionLocalBySid(sessionid, c_sid, c_uid, c_did, c_members, c_username, c_gpo)) { // Session still exists — update local copy with cluster data cur->_members = c_members; cur->_username = c_username; cur->setGPOResults(c_gpo); } else { // Session removed on another node — purge local copy SessionData *prev = nullptr; for (SessionData *p = _firstData; p; p = p->_next) { if (p == cur) break; prev = p; } if (prev) prev->_next = cur->_next; if (cur == _firstData) _firstData = cur->_next; if (cur == _lastData) _lastData = prev; cur->_next = nullptr; delete cur; removeLocal(sessionid); return nullptr; } } return cur; } } } // Not found locally — fetch from cluster peers by SID // Not found locally — fetch from cluster peers if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid sid, uid, did; std::vector<uuid::uuid> members; Loading @@ -466,14 +551,8 @@ const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ imported->_username = username; imported->setGPOResults(gpo_results); std::lock_guard<std::mutex> guard(_SessionLock); if (!_firstData) { _firstData = imported; _lastData = _firstData; } else { _lastData->_next = imported; _lastData = _lastData->_next; } std::lock_guard<std::mutex> guard(_lock); appendLocal(imported); return imported; } } Loading @@ -481,49 +560,20 @@ const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ return nullptr; } void authdb::Session::remSession(uuid::uuid sessionid){ // Always remove from cluster (covers all nodes) void authdb::ClusterSession::remSession(uuid::uuid sessionid){ // Remove from cluster on ALL nodes if (g_Cluster && g_Cluster->isRunning()) { g_Cluster->removeSessionBySid(sessionid); } // Remove from local linked list if present std::lock_guard<std::mutex> guard(_SessionLock); SessionData *prev=nullptr; for(SessionData *cur=_firstData; cur; cur=cur->_next){ if(cur->_sid==sessionid){ if(prev) prev->_next=cur->_next; if(cur==_firstData) _firstData=cur->_next; if(cur==_lastData) _lastData=prev; cur->_next=nullptr; delete cur; break; } prev=cur; } // Remove from local cache std::lock_guard<std::mutex> guard(_lock); removeLocal(sessionid); } void authdb::Session::relSession(AuthBackend &backend,uuid::uuid sessionid){ std::lock_guard<std::mutex> guard(_SessionLock); Group group; std::string username; SessionData *cursess=nullptr; for(SessionData *cur=_firstData; cur; cur=cur->_next){ if(cur->_sid==sessionid){ cursess=cur; break; } } void authdb::ClusterSession::relSession(AuthBackend &backend,uuid::uuid sessionid){ { std::lock_guard<std::mutex> guard(_lock); SessionData *cursess = findLocal(sessionid); // Not found locally — try to import from cluster if (!cursess && g_Cluster && g_Cluster->isRunning()) { Loading @@ -535,79 +585,59 @@ void authdb::Session::relSession(AuthBackend &backend,uuid::uuid sessionid){ cursess = new SessionData(sid, uid, did, members); cursess->_username = c_username; cursess->setGPOResults(gpo_results); if(!_firstData){ _firstData = cursess; _lastData = _firstData; }else{ _lastData->_next = cursess; _lastData = _lastData->_next; } appendLocal(cursess); } } if (!cursess) throw AuthBackendError("reload session: sessionid not found !"); cursess->_members.clear(); std::shared_ptr<authdb::AuthData::Record> cur=std::make_shared<authdb::AuthData::Record>(); reloadSessionData(backend, cursess); size_t rd=sizeof(authdb::AuthHeader),end=backend.end(); while(rd<end){ cur->type=EmptyData; backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if(cur->type == UserData && strcmp(cur->fieldname,"username")==0 && uuid::uuid(cur->ruid)==cursess->_uid.value){ const std::shared_ptr<unsigned char[]>tmp(new unsigned char[cur->datasize]); backend.read(tmp.get(),cur->datasize); username=reinterpret_cast<char*>(tmp.get()); // Push updated data to cluster if (g_Cluster && g_Cluster->isRunning()) { g_Cluster->pushSession(*cursess); } if(cur->type == GroupData && strcmp(cur->fieldname,"groupname")==0){ std::shared_ptr<class GroupData> grpi=std::make_shared<class GroupData>(cur->ruid); size_t upos=sizeof(authdb::AuthHeader); group.info(backend,*grpi,upos); if(grpi->isMember(cursess->_uid.value)) cursess->_members.emplace_back(cur->ruid); } } cursess->_username=username; void authdb::ClusterSession::listSessions(std::vector<SessionInfo> &out){ out.clear(); std::set<std::string> seen_sids; // Update cluster with refreshed session data if (g_Cluster && g_Cluster->isRunning()) { g_Cluster->pushSession(*cursess); } // Local sessions { std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); for(SessionData *cur=_firstData; cur; cur=cur->_next){ SessionInfo info; cur->getSid(info.sid); cur->getUid(info.uid); cur->getDid(info.did); info.username = cur->getUsername(); seen_sids.insert(std::string(info.sid.c_str())); out.push_back(std::move(info)); } const authdb::SessionData *authdb::Session::firstData() const{ std::lock_guard<std::mutex> guard(_SessionLock); return _firstData; } void authdb::Session::cleanupExpired(){ auto now=std::chrono::steady_clock::now(); SessionData *prev=nullptr; SessionData *cur=_firstData; while(cur){ auto age=std::chrono::duration_cast<std::chrono::hours>(now - cur->_created).count(); if(age >= 24){ // Remove from cluster // Cluster sessions if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid uid, did; cur->getUid(uid); cur->getDid(did); g_Cluster->removeSession(uid, did); std::vector<Cluster::SessionInfo> csessions; g_Cluster->listAllSessions(csessions); for (const auto &cs : csessions) { std::string sidstr = cs.sid.c_str(); if (seen_sids.count(sidstr)) continue; seen_sids.insert(sidstr); SessionInfo info; info.sid = cs.sid; info.uid = cs.uid; info.did = cs.did; info.username = cs.username; out.push_back(std::move(info)); } } } SessionData *next=cur->_next; if(prev) prev->_next=next; if(cur==_firstData) Loading Loading
src/session.cpp +240 −210 Changes for src/session.cpp: 240 added lines, 210 removed lines. Original line number Diff line number Diff line Loading @@ -181,28 +181,15 @@ void authdb::SessionData::setGPOResults(const std::vector<std::pair<uuid::uuid, } } authdb::Session::Session() { // ===== LocalSession ===== authdb::LocalSession::LocalSession() { _firstData=nullptr; _lastData=nullptr; } authdb::Session::Session(const Session& src) : Session(){ std::lock_guard<std::mutex> guard(_SessionLock); for(SessionData *cur=src._firstData; cur; cur=cur->_next){ if(!_firstData){ _firstData=new SessionData(cur->_sid,cur->_uid,cur->_did,cur->_members); _lastData=_firstData; }else{ _lastData->_next=new SessionData(cur->_sid,cur->_uid,cur->_did,cur->_members); _lastData=_lastData->_next; } _lastData->_username=cur->_username; } } void authdb::Session::clear(){ void authdb::LocalSession::clear(){ std::lock_guard<std::mutex> guard(_lock); SessionData *del=_firstData; while(del){ SessionData *next=del->_next; Loading @@ -214,78 +201,83 @@ void authdb::Session::clear(){ _lastData=nullptr; } authdb::Session::~Session(){ authdb::LocalSession::~LocalSession(){ clear(); }; const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid::uuid domainid,uuid::uuid userid){ } // --- Cluster deduplication: check if session for this user+domain already exists --- if (g_Cluster && g_Cluster->isRunning()) { // Check local sessions first (same user+domain) { std::lock_guard<std::mutex> guard(_SessionLock); authdb::SessionData *authdb::LocalSession::findLocal(uuid::uuid sessionid){ for(SessionData *cur=_firstData; cur; cur=cur->_next){ uuid::uuid cur_uid, cur_did; cur->getUid(cur_uid); cur->getDid(cur_did); if (cur_uid == userid && cur_did == domainid) { return cur; // Reuse existing local session } if(cur->_sid==sessionid) return cur; } return nullptr; } // Check cluster peers for existing session uuid::uuid cluster_sid; std::vector<uuid::uuid> cluster_members; std::string cluster_username; std::vector<std::pair<uuid::uuid, bool>> cluster_gpo; if (g_Cluster->fetchSession(userid, domainid, cluster_sid, cluster_members, cluster_username, cluster_gpo)) { // Session exists on another node, import it locally SessionData *imported = new SessionData(cluster_sid, userid, domainid, cluster_members); imported->_username = cluster_username; imported->setGPOResults(cluster_gpo); std::lock_guard<std::mutex> guard(_SessionLock); void authdb::LocalSession::appendLocal(SessionData *sess){ if(!_firstData){ _firstData = imported; _firstData=sess; _lastData=_firstData; }else{ _lastData->_next = imported; _lastData->_next=sess; _lastData=_lastData->_next; } return imported; } } else { // No cluster: still deduplicate locally std::lock_guard<std::mutex> guard(_SessionLock); void authdb::LocalSession::removeLocal(uuid::uuid sessionid){ SessionData *prev=nullptr; for(SessionData *cur=_firstData; cur; cur=cur->_next){ uuid::uuid cur_uid, cur_did; cur->getUid(cur_uid); cur->getDid(cur_did); if (cur_uid == userid && cur_did == domainid) { return cur; if(cur->_sid==sessionid){ if(prev) prev->_next=cur->_next; if(cur==_firstData) _firstData=cur->_next; if(cur==_lastData) _lastData=prev; cur->_next=nullptr; delete cur; return; } prev=cur; } } void authdb::LocalSession::cleanupExpired(){ auto now=std::chrono::steady_clock::now(); SessionData *prev=nullptr; SessionData *cur=_firstData; while(cur){ auto age=std::chrono::duration_cast<std::chrono::hours>(now - cur->_created).count(); if(age >= 24){ SessionData *next=cur->_next; if(prev) prev->_next=next; if(cur==_firstData) _firstData=next; if(cur==_lastData) _lastData=prev; cur->_next=nullptr; delete cur; cur=next; }else{ prev=cur; cur=cur->_next; } } } static authdb::SessionData *createSessionData(authdb::AuthBackend &backend, uuid::uuid domainid, uuid::uuid userid){ using namespace authdb; std::string username; std::shared_ptr<authdb::AuthData::Record> cur=std::make_shared<authdb::AuthData::Record>(); std::shared_ptr<AuthData::Record> cur=std::make_shared<AuthData::Record>(); size_t rd=sizeof(authdb::AuthHeader),end=backend.end(); size_t rd=sizeof(AuthHeader),end=backend.end(); while(rd<end){ cur->type=EmptyData; backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if(cur->type == UserData && strcmp(cur->fieldname,"username")==0 && userid==cur->ruid){ unsigned char *tmp = new unsigned char[cur->datasize]; backend.read(tmp,cur->datasize); username=reinterpret_cast<char*>(tmp); Loading @@ -293,20 +285,16 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid } } std::shared_ptr<std::vector<uuid::uuid>> mbs = std::make_shared<std::vector<uuid::uuid>>(); rd=sizeof(authdb::AuthHeader); rd=sizeof(AuthHeader); while(rd<end){ backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if( !uuid::uuid(cur->ruid).empty() && cur->type == GroupData && strcmp(cur->fieldname,"groupname")==0){ Group group; std::shared_ptr<class GroupData> grpi=std::make_shared<class GroupData>(cur->ruid); size_t upos=sizeof(authdb::AuthHeader); size_t upos=sizeof(AuthHeader); group.info(backend,*grpi,upos); if(grpi->isMember(userid)){ mbs->emplace_back(cur->ruid); Loading @@ -319,27 +307,21 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid SessionData *newSession=new SessionData(sid,userid,domainid,*mbs); newSession->_username=username; newSession->_GPOResult.next=nullptr; SessionData::GPOResult *gpores=&newSession->_GPOResult; Gpo gpo; std::vector<uuid::uuid> allow; rd=sizeof(authdb::AuthHeader); rd=sizeof(AuthHeader); while(rd<end){ backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if(cur->type == PolicyData && strcmp(cur->fieldname,"gponame")==0){ std::shared_ptr<class GpoData> gpodat=std::make_shared<class GpoData>(cur->ruid); size_t upos=sizeof(authdb::AuthHeader); size_t upos=sizeof(AuthHeader); gpo.info(backend,*gpodat,upos); if(!gpores->GPOId.empty()){ gpores->next=new SessionData::GPOResult(); Loading Loading @@ -373,42 +355,156 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid } if(!found){ bool defval=(strcmp(gpo_default[i][3],"true")==0); // Add to session result if(!gpores->GPOId.empty()){ gpores->next=new SessionData::GPOResult(); gpores=gpores->next; } gpores->GPOId=defid; gpores->GPORes=defval; // Create the missing GPO record in the backend try { GpoData gdat(defid); gdat.setName(gpo_default[i][1]); gdat.setDesc(gpo_default[i][2]); gdat.setGpoValue(defval); gpo.create(backend, &gdat); } catch (...) { // GPO may already exist from concurrent creation } catch (...) {} } } return newSession; } static void reloadSessionData(authdb::AuthBackend &backend, authdb::SessionData *cursess){ using namespace authdb; Group group; std::string username; cursess->_members.clear(); std::shared_ptr<AuthData::Record> cur=std::make_shared<AuthData::Record>(); size_t rd=sizeof(AuthHeader),end=backend.end(); while(rd<end){ cur->type=EmptyData; backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if(cur->type == UserData && strcmp(cur->fieldname,"username")==0 && uuid::uuid(cur->ruid)==cursess->_uid.value){ const std::shared_ptr<unsigned char[]>tmp(new unsigned char[cur->datasize]); backend.read(tmp.get(),cur->datasize); username=reinterpret_cast<char*>(tmp.get()); } if(cur->type == GroupData && strcmp(cur->fieldname,"groupname")==0){ std::shared_ptr<class GroupData> grpi=std::make_shared<class GroupData>(cur->ruid); size_t upos=sizeof(AuthHeader); group.info(backend,*grpi,upos); if(grpi->isMember(cursess->_uid.value)) cursess->_members.emplace_back(cur->ruid); } } cursess->_username=username; } const authdb::SessionData *authdb::LocalSession::addSession(AuthBackend &backend,uuid::uuid domainid,uuid::uuid userid){ { std::lock_guard<std::mutex> guard(_SessionLock); std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); for (SessionData *cur = _firstData; cur; cur = cur->_next) { uuid::uuid cur_uid, cur_did; cur->getUid(cur_uid); cur->getDid(cur_did); if (cur_uid == userid && cur_did == domainid) return cur; } } SessionData *newSession = createSessionData(backend, domainid, userid); std::lock_guard<std::mutex> guard(_lock); appendLocal(newSession); return newSession; } const authdb::SessionData *authdb::LocalSession::getSession(uuid::uuid sessionid){ std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); return findLocal(sessionid); } if(!_firstData){ _firstData=newSession; _lastData=_firstData; }else{ _lastData->_next=newSession; _lastData=_lastData->_next; void authdb::LocalSession::remSession(uuid::uuid sessionid){ std::lock_guard<std::mutex> guard(_lock); removeLocal(sessionid); } void authdb::LocalSession::relSession(AuthBackend &backend,uuid::uuid sessionid){ std::lock_guard<std::mutex> guard(_lock); SessionData *cursess = findLocal(sessionid); if(!cursess) throw AuthBackendError("reload session: sessionid not found !"); reloadSessionData(backend, cursess); } void authdb::LocalSession::listSessions(std::vector<SessionInfo> &out){ std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); out.clear(); for(SessionData *cur=_firstData; cur; cur=cur->_next){ SessionInfo info; cur->getSid(info.sid); cur->getUid(info.uid); cur->getDid(info.did); info.username = cur->getUsername(); out.push_back(std::move(info)); } } // ===== ClusterSession ===== authdb::ClusterSession::ClusterSession() : LocalSession() {} authdb::ClusterSession::~ClusterSession() {} const authdb::SessionData *authdb::ClusterSession::addSession(AuthBackend &backend,uuid::uuid domainid,uuid::uuid userid){ // Check local cache first { std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); for (SessionData *cur = _firstData; cur; cur = cur->_next) { uuid::uuid cur_uid, cur_did; cur->getUid(cur_uid); cur->getDid(cur_did); if (cur_uid == userid && cur_did == domainid) return cur; } } // Check cluster for existing session if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid cluster_sid; std::vector<uuid::uuid> cluster_members; std::string cluster_username; std::vector<std::pair<uuid::uuid, bool>> cluster_gpo; if (g_Cluster->fetchSession(userid, domainid, cluster_sid, cluster_members, cluster_username, cluster_gpo)) { SessionData *imported = new SessionData(cluster_sid, userid, domainid, cluster_members); imported->_username = cluster_username; imported->setGPOResults(cluster_gpo); std::lock_guard<std::mutex> guard(_lock); appendLocal(imported); return imported; } } // Create new session SessionData *newSession = createSessionData(backend, domainid, userid); { std::lock_guard<std::mutex> guard(_lock); appendLocal(newSession); } // Push to cluster for replication if (g_Cluster && g_Cluster->isRunning()) { g_Cluster->pushSession(*newSession); Loading @@ -417,12 +513,12 @@ const authdb::SessionData *authdb::Session::addSession(AuthBackend &backend,uuid return newSession; } const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ const authdb::SessionData *authdb::ClusterSession::getSession(uuid::uuid sessionid){ { std::lock_guard<std::mutex> guard(_SessionLock); std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); for(SessionData *cur=_firstData; cur; cur=cur->_next){ if(cur->_sid==sessionid){ SessionData *cur = findLocal(sessionid); if (cur) { // Sync with cluster session_store_ (local memory only, no network) if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid c_sid, c_uid, c_did; Loading @@ -431,31 +527,20 @@ const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ std::vector<std::pair<uuid::uuid, bool>> c_gpo; if (g_Cluster->fetchSessionLocalBySid(sessionid, c_sid, c_uid, c_did, c_members, c_username, c_gpo)) { // Session still exists — update local copy with cluster data cur->_members = c_members; cur->_username = c_username; cur->setGPOResults(c_gpo); } else { // Session removed on another node — purge local copy SessionData *prev = nullptr; for (SessionData *p = _firstData; p; p = p->_next) { if (p == cur) break; prev = p; } if (prev) prev->_next = cur->_next; if (cur == _firstData) _firstData = cur->_next; if (cur == _lastData) _lastData = prev; cur->_next = nullptr; delete cur; removeLocal(sessionid); return nullptr; } } return cur; } } } // Not found locally — fetch from cluster peers by SID // Not found locally — fetch from cluster peers if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid sid, uid, did; std::vector<uuid::uuid> members; Loading @@ -466,14 +551,8 @@ const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ imported->_username = username; imported->setGPOResults(gpo_results); std::lock_guard<std::mutex> guard(_SessionLock); if (!_firstData) { _firstData = imported; _lastData = _firstData; } else { _lastData->_next = imported; _lastData = _lastData->_next; } std::lock_guard<std::mutex> guard(_lock); appendLocal(imported); return imported; } } Loading @@ -481,49 +560,20 @@ const authdb::SessionData *authdb::Session::getSession(uuid::uuid sessionid){ return nullptr; } void authdb::Session::remSession(uuid::uuid sessionid){ // Always remove from cluster (covers all nodes) void authdb::ClusterSession::remSession(uuid::uuid sessionid){ // Remove from cluster on ALL nodes if (g_Cluster && g_Cluster->isRunning()) { g_Cluster->removeSessionBySid(sessionid); } // Remove from local linked list if present std::lock_guard<std::mutex> guard(_SessionLock); SessionData *prev=nullptr; for(SessionData *cur=_firstData; cur; cur=cur->_next){ if(cur->_sid==sessionid){ if(prev) prev->_next=cur->_next; if(cur==_firstData) _firstData=cur->_next; if(cur==_lastData) _lastData=prev; cur->_next=nullptr; delete cur; break; } prev=cur; } // Remove from local cache std::lock_guard<std::mutex> guard(_lock); removeLocal(sessionid); } void authdb::Session::relSession(AuthBackend &backend,uuid::uuid sessionid){ std::lock_guard<std::mutex> guard(_SessionLock); Group group; std::string username; SessionData *cursess=nullptr; for(SessionData *cur=_firstData; cur; cur=cur->_next){ if(cur->_sid==sessionid){ cursess=cur; break; } } void authdb::ClusterSession::relSession(AuthBackend &backend,uuid::uuid sessionid){ { std::lock_guard<std::mutex> guard(_lock); SessionData *cursess = findLocal(sessionid); // Not found locally — try to import from cluster if (!cursess && g_Cluster && g_Cluster->isRunning()) { Loading @@ -535,79 +585,59 @@ void authdb::Session::relSession(AuthBackend &backend,uuid::uuid sessionid){ cursess = new SessionData(sid, uid, did, members); cursess->_username = c_username; cursess->setGPOResults(gpo_results); if(!_firstData){ _firstData = cursess; _lastData = _firstData; }else{ _lastData->_next = cursess; _lastData = _lastData->_next; } appendLocal(cursess); } } if (!cursess) throw AuthBackendError("reload session: sessionid not found !"); cursess->_members.clear(); std::shared_ptr<authdb::AuthData::Record> cur=std::make_shared<authdb::AuthData::Record>(); reloadSessionData(backend, cursess); size_t rd=sizeof(authdb::AuthHeader),end=backend.end(); while(rd<end){ cur->type=EmptyData; backend.setPos(rd); backend.read(reinterpret_cast<unsigned char*>(cur.get()),sizeof(AuthData::Record)); rd=backend.getPos()+cur->datasize; if(cur->type == UserData && strcmp(cur->fieldname,"username")==0 && uuid::uuid(cur->ruid)==cursess->_uid.value){ const std::shared_ptr<unsigned char[]>tmp(new unsigned char[cur->datasize]); backend.read(tmp.get(),cur->datasize); username=reinterpret_cast<char*>(tmp.get()); // Push updated data to cluster if (g_Cluster && g_Cluster->isRunning()) { g_Cluster->pushSession(*cursess); } if(cur->type == GroupData && strcmp(cur->fieldname,"groupname")==0){ std::shared_ptr<class GroupData> grpi=std::make_shared<class GroupData>(cur->ruid); size_t upos=sizeof(authdb::AuthHeader); group.info(backend,*grpi,upos); if(grpi->isMember(cursess->_uid.value)) cursess->_members.emplace_back(cur->ruid); } } cursess->_username=username; void authdb::ClusterSession::listSessions(std::vector<SessionInfo> &out){ out.clear(); std::set<std::string> seen_sids; // Update cluster with refreshed session data if (g_Cluster && g_Cluster->isRunning()) { g_Cluster->pushSession(*cursess); } // Local sessions { std::lock_guard<std::mutex> guard(_lock); cleanupExpired(); for(SessionData *cur=_firstData; cur; cur=cur->_next){ SessionInfo info; cur->getSid(info.sid); cur->getUid(info.uid); cur->getDid(info.did); info.username = cur->getUsername(); seen_sids.insert(std::string(info.sid.c_str())); out.push_back(std::move(info)); } const authdb::SessionData *authdb::Session::firstData() const{ std::lock_guard<std::mutex> guard(_SessionLock); return _firstData; } void authdb::Session::cleanupExpired(){ auto now=std::chrono::steady_clock::now(); SessionData *prev=nullptr; SessionData *cur=_firstData; while(cur){ auto age=std::chrono::duration_cast<std::chrono::hours>(now - cur->_created).count(); if(age >= 24){ // Remove from cluster // Cluster sessions if (g_Cluster && g_Cluster->isRunning()) { uuid::uuid uid, did; cur->getUid(uid); cur->getDid(did); g_Cluster->removeSession(uid, did); std::vector<Cluster::SessionInfo> csessions; g_Cluster->listAllSessions(csessions); for (const auto &cs : csessions) { std::string sidstr = cs.sid.c_str(); if (seen_sids.count(sidstr)) continue; seen_sids.insert(sidstr); SessionInfo info; info.sid = cs.sid; info.uid = cs.uid; info.did = cs.did; info.username = cs.username; out.push_back(std::move(info)); } } } SessionData *next=cur->_next; if(prev) prev->_next=next; if(cur==_firstData) Loading