Loading debian/changelog +11 −0 Original line number Diff line number Diff line authdb (20260426+1) unstable; urgency=medium * file backend vacuum: check write/ftruncate/lseek return values, throw on failure instead of silently corrupting the database * file backend: check read/write return values in getRevesion() and newRevesion() * Fix -Wunused-result warnings: check mkdir/chown return values in authdb.cpp, log failures to stderr -- Jan Koester <jan.koester@tuxist.de> Sat, 26 Apr 2026 17:00:00 +0200 authdb (20260424+8) unstable; urgency=medium * Cluster: use multi-store protocol for session data (store_id=1). Loading src/authdb.cpp +16 −8 Original line number Diff line number Diff line Loading @@ -683,11 +683,15 @@ int main(int argc,char *argv[]){ #ifndef _WIN32 { struct stat st; if (stat("/var/log/authdb", &st) != 0) mkdir("/var/log/authdb", 0750); if (stat("/var/log/authdb", &st) != 0) { if (mkdir("/var/log/authdb", 0750) != 0) std::cerr << "mkdir /var/log/authdb failed: " << strerror(errno) << std::endl; } struct passwd *lpw = getpwnam("authdb"); if (lpw) chown("/var/log/authdb", lpw->pw_uid, lpw->pw_gid); if (lpw) { if (chown("/var/log/authdb", lpw->pw_uid, lpw->pw_gid) != 0) std::cerr << "chown /var/log/authdb failed: " << strerror(errno) << std::endl; } } authdb::g_Log.open("/var/log/authdb/access.log", "/var/log/authdb/error.log"); #else Loading Loading @@ -879,18 +883,22 @@ int main(int argc,char *argv[]){ fs::path parentDir = fs::path(backendPath).parent_path(); if (fs::is_directory(parentDir)) { for (auto &entry : fs::recursive_directory_iterator(parentDir)) { chown(entry.path().c_str(), pw->pw_uid, pw->pw_gid); if (chown(entry.path().c_str(), pw->pw_uid, pw->pw_gid) != 0) std::cerr << "chown " << entry.path() << " failed: " << strerror(errno) << std::endl; } chown(parentDir.c_str(), pw->pw_uid, pw->pw_gid); if (chown(parentDir.c_str(), pw->pw_uid, pw->pw_gid) != 0) std::cerr << "chown " << parentDir << " failed: " << strerror(errno) << std::endl; } } if (clusterEnabled && !ccfg.store_path.empty()) { namespace fs = std::filesystem; if (fs::is_directory(ccfg.store_path)) { for (auto &entry : fs::recursive_directory_iterator(ccfg.store_path)) { chown(entry.path().c_str(), pw->pw_uid, pw->pw_gid); if (chown(entry.path().c_str(), pw->pw_uid, pw->pw_gid) != 0) std::cerr << "chown " << entry.path() << " failed: " << strerror(errno) << std::endl; } chown(ccfg.store_path.c_str(), pw->pw_uid, pw->pw_gid); if (chown(ccfg.store_path.c_str(), pw->pw_uid, pw->pw_gid) != 0) std::cerr << "chown " << ccfg.store_path << " failed: " << strerror(errno) << std::endl; } } if (setgid(pw->pw_gid) != 0) { Loading src/backends/file.cpp +32 −9 Original line number Diff line number Diff line Loading @@ -422,7 +422,10 @@ size_t authdb::File::getRevesion(){ setPos(0); AuthHeader head; ::read(_FileDes,&head,sizeof(head)); if (::read(_FileDes,&head,sizeof(head)) != sizeof(head)) { setPos(cur); return 0; } setPos(cur); Loading @@ -437,10 +440,16 @@ void authdb::File::newRevesion(){ size_t cur=getPos(); setPos(0); AuthHeader head; ::read(_FileDes,&head,sizeof(head)); if (::read(_FileDes,&head,sizeof(head)) != sizeof(head)) { setPos(cur); return; } ++head.Revesion; setPos(0); ::write(_FileDes,&head,sizeof(head)); if (::write(_FileDes,&head,sizeof(head)) != sizeof(head)) { setPos(cur); return; } setPos(cur); #endif } Loading Loading @@ -554,7 +563,11 @@ void authdb::File::vacuum(){ std::map<std::tuple<std::string,std::string,int>, RecordEntry> dedup; std::vector<std::tuple<std::string,std::string,int>> insertOrder; size_t fileEnd = lseek(_FileDes, 0, SEEK_END); off_t fileEndOff = lseek(_FileDes, 0, SEEK_END); if (fileEndOff < 0) { throw AuthBackendError("vacuum: lseek failed"); } size_t fileEnd = static_cast<size_t>(fileEndOff); size_t rd = sizeof(AuthHeader); while (rd < fileEnd) { Loading Loading @@ -596,27 +609,37 @@ void authdb::File::vacuum(){ // 3. Rewrite: header + valid records lseek(_FileDes, 0, SEEK_SET); ::write(_FileDes, &head, sizeof(head)); if (::write(_FileDes, &head, sizeof(head)) != sizeof(head)) { throw AuthBackendError("vacuum: failed to write header"); } for (auto &key : insertOrder) { auto it = dedup.find(key); if (it == dedup.end()) continue; auto &entry = it->second; entry.rec.data = nullptr; // pointer not meaningful on disk ::write(_FileDes, &entry.rec, sizeof(AuthData::Record)); if (::write(_FileDes, &entry.rec, sizeof(AuthData::Record)) != sizeof(AuthData::Record)) { throw AuthBackendError("vacuum: failed to write record"); } if (!entry.data.empty()) { ::write(_FileDes, entry.data.data(), entry.data.size()); if (::write(_FileDes, entry.data.data(), entry.data.size()) != (ssize_t)entry.data.size()) { throw AuthBackendError("vacuum: failed to write record data"); } } } // 4. Truncate file at current write position off_t newEnd = lseek(_FileDes, 0, SEEK_CUR); ftruncate(_FileDes, newEnd); if (newEnd < 0 || ftruncate(_FileDes, newEnd) != 0) { throw AuthBackendError("vacuum: failed to truncate file"); } // 5. Bump revision ++head.Revesion; lseek(_FileDes, 0, SEEK_SET); ::write(_FileDes, &head, sizeof(head)); if (::write(_FileDes, &head, sizeof(head)) != sizeof(head)) { throw AuthBackendError("vacuum: failed to write updated header"); } #endif } Loading Loading
debian/changelog +11 −0 Original line number Diff line number Diff line authdb (20260426+1) unstable; urgency=medium * file backend vacuum: check write/ftruncate/lseek return values, throw on failure instead of silently corrupting the database * file backend: check read/write return values in getRevesion() and newRevesion() * Fix -Wunused-result warnings: check mkdir/chown return values in authdb.cpp, log failures to stderr -- Jan Koester <jan.koester@tuxist.de> Sat, 26 Apr 2026 17:00:00 +0200 authdb (20260424+8) unstable; urgency=medium * Cluster: use multi-store protocol for session data (store_id=1). Loading
src/authdb.cpp +16 −8 Original line number Diff line number Diff line Loading @@ -683,11 +683,15 @@ int main(int argc,char *argv[]){ #ifndef _WIN32 { struct stat st; if (stat("/var/log/authdb", &st) != 0) mkdir("/var/log/authdb", 0750); if (stat("/var/log/authdb", &st) != 0) { if (mkdir("/var/log/authdb", 0750) != 0) std::cerr << "mkdir /var/log/authdb failed: " << strerror(errno) << std::endl; } struct passwd *lpw = getpwnam("authdb"); if (lpw) chown("/var/log/authdb", lpw->pw_uid, lpw->pw_gid); if (lpw) { if (chown("/var/log/authdb", lpw->pw_uid, lpw->pw_gid) != 0) std::cerr << "chown /var/log/authdb failed: " << strerror(errno) << std::endl; } } authdb::g_Log.open("/var/log/authdb/access.log", "/var/log/authdb/error.log"); #else Loading Loading @@ -879,18 +883,22 @@ int main(int argc,char *argv[]){ fs::path parentDir = fs::path(backendPath).parent_path(); if (fs::is_directory(parentDir)) { for (auto &entry : fs::recursive_directory_iterator(parentDir)) { chown(entry.path().c_str(), pw->pw_uid, pw->pw_gid); if (chown(entry.path().c_str(), pw->pw_uid, pw->pw_gid) != 0) std::cerr << "chown " << entry.path() << " failed: " << strerror(errno) << std::endl; } chown(parentDir.c_str(), pw->pw_uid, pw->pw_gid); if (chown(parentDir.c_str(), pw->pw_uid, pw->pw_gid) != 0) std::cerr << "chown " << parentDir << " failed: " << strerror(errno) << std::endl; } } if (clusterEnabled && !ccfg.store_path.empty()) { namespace fs = std::filesystem; if (fs::is_directory(ccfg.store_path)) { for (auto &entry : fs::recursive_directory_iterator(ccfg.store_path)) { chown(entry.path().c_str(), pw->pw_uid, pw->pw_gid); if (chown(entry.path().c_str(), pw->pw_uid, pw->pw_gid) != 0) std::cerr << "chown " << entry.path() << " failed: " << strerror(errno) << std::endl; } chown(ccfg.store_path.c_str(), pw->pw_uid, pw->pw_gid); if (chown(ccfg.store_path.c_str(), pw->pw_uid, pw->pw_gid) != 0) std::cerr << "chown " << ccfg.store_path << " failed: " << strerror(errno) << std::endl; } } if (setgid(pw->pw_gid) != 0) { Loading
src/backends/file.cpp +32 −9 Original line number Diff line number Diff line Loading @@ -422,7 +422,10 @@ size_t authdb::File::getRevesion(){ setPos(0); AuthHeader head; ::read(_FileDes,&head,sizeof(head)); if (::read(_FileDes,&head,sizeof(head)) != sizeof(head)) { setPos(cur); return 0; } setPos(cur); Loading @@ -437,10 +440,16 @@ void authdb::File::newRevesion(){ size_t cur=getPos(); setPos(0); AuthHeader head; ::read(_FileDes,&head,sizeof(head)); if (::read(_FileDes,&head,sizeof(head)) != sizeof(head)) { setPos(cur); return; } ++head.Revesion; setPos(0); ::write(_FileDes,&head,sizeof(head)); if (::write(_FileDes,&head,sizeof(head)) != sizeof(head)) { setPos(cur); return; } setPos(cur); #endif } Loading Loading @@ -554,7 +563,11 @@ void authdb::File::vacuum(){ std::map<std::tuple<std::string,std::string,int>, RecordEntry> dedup; std::vector<std::tuple<std::string,std::string,int>> insertOrder; size_t fileEnd = lseek(_FileDes, 0, SEEK_END); off_t fileEndOff = lseek(_FileDes, 0, SEEK_END); if (fileEndOff < 0) { throw AuthBackendError("vacuum: lseek failed"); } size_t fileEnd = static_cast<size_t>(fileEndOff); size_t rd = sizeof(AuthHeader); while (rd < fileEnd) { Loading Loading @@ -596,27 +609,37 @@ void authdb::File::vacuum(){ // 3. Rewrite: header + valid records lseek(_FileDes, 0, SEEK_SET); ::write(_FileDes, &head, sizeof(head)); if (::write(_FileDes, &head, sizeof(head)) != sizeof(head)) { throw AuthBackendError("vacuum: failed to write header"); } for (auto &key : insertOrder) { auto it = dedup.find(key); if (it == dedup.end()) continue; auto &entry = it->second; entry.rec.data = nullptr; // pointer not meaningful on disk ::write(_FileDes, &entry.rec, sizeof(AuthData::Record)); if (::write(_FileDes, &entry.rec, sizeof(AuthData::Record)) != sizeof(AuthData::Record)) { throw AuthBackendError("vacuum: failed to write record"); } if (!entry.data.empty()) { ::write(_FileDes, entry.data.data(), entry.data.size()); if (::write(_FileDes, entry.data.data(), entry.data.size()) != (ssize_t)entry.data.size()) { throw AuthBackendError("vacuum: failed to write record data"); } } } // 4. Truncate file at current write position off_t newEnd = lseek(_FileDes, 0, SEEK_CUR); ftruncate(_FileDes, newEnd); if (newEnd < 0 || ftruncate(_FileDes, newEnd) != 0) { throw AuthBackendError("vacuum: failed to truncate file"); } // 5. Bump revision ++head.Revesion; lseek(_FileDes, 0, SEEK_SET); ::write(_FileDes, &head, sizeof(head)); if (::write(_FileDes, &head, sizeof(head)) != sizeof(head)) { throw AuthBackendError("vacuum: failed to write updated header"); } #endif } Loading