Archived
1
0
This commit is contained in:
Jeff Becker 2016-10-15 13:53:35 -04:00
parent d31ca5b6a7
commit 9ae0b0ef5b
No known key found for this signature in database
GPG Key ID: AB950234D6EA286B
11 changed files with 210 additions and 25 deletions

View File

@ -53,6 +53,10 @@ int main(int argc, char * argv[]) {
return 1; return 1;
} }
if (nntpconf.find("authdb") != nntpconf.end()) {
nntp.SetLoginDB(nntpconf["authdb"]);
}
auto & a = nntpconf["bind"]; auto & a = nntpconf["bind"];
try { try {

View File

@ -1,6 +1,6 @@
[nntp] [nntp]
bind = [::]:1199 bind = [::]:1199
authdb=auth.txt
[storage] [storage]
path = ./storage/ path = ./storage/

View File

@ -219,8 +219,8 @@ namespace nntpchan
std::string B64Encode(const uint8_t * data, const std::size_t l) std::string B64Encode(const uint8_t * data, const std::size_t l)
{ {
std::string out; std::string out;
out.reserve(i2p::data::Base64EncodingBufferSize(l)); out.resize(i2p::data::Base64EncodingBufferSize(l));
i2p::data::ByteStreamToBase64(data, l, &out[0], out.capacity()); i2p::data::ByteStreamToBase64(data, l, &out[0], out.size());
return out; return out;
} }

View File

@ -12,6 +12,9 @@ namespace nntpchan {
if(c == '\n') { if(c == '\n') {
OnLine(d, idx-2); OnLine(d, idx-2);
d += idx; d += idx;
} else if (c == '\r' && d[idx] == '\n') {
OnLine(d, idx-2);
d += idx + 1;
} }
} }
} }

View File

@ -7,21 +7,18 @@
namespace nntpchan namespace nntpchan
{ {
HashedCredDB::HashedCredDB(std::istream & i) :
m_instream(i) {}
bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd) bool HashedCredDB::CheckLogin(const std::string & user, const std::string & passwd)
{ {
std::unique_lock<std::mutex> lock(m_access); std::unique_lock<std::mutex> lock(m_access);
m_found = false; m_found = false;
m_user = user; m_user = user;
m_passwd = passwd; m_passwd = passwd;
m_instream.seekg(0, std::ios::end); m_instream->seekg(0, std::ios::end);
const auto l = m_instream.tellg(); const auto l = m_instream->tellg();
m_instream.seekg(0, std::ios::beg); m_instream->seekg(0, std::ios::beg);
char * buff = new char[l]; char * buff = new char[l];
// read file // read file
m_instream.read(buff, l); m_instream->read(buff, l);
OnData(buff, l); OnData(buff, l);
delete [] buff; delete [] buff;
return m_found; return m_found;
@ -50,6 +47,18 @@ namespace nntpchan
return Hash(m_passwd, salt) == cred; return Hash(m_passwd, salt) == cred;
} }
void HashedCredDB::HandleLine(const std::string &line)
{
if(m_found) return;
if(ProcessLine(line))
m_found = true;
}
void HashedCredDB::SetStream(std::istream * s)
{
m_instream = s;
}
std::string HashedCredDB::Hash(const std::string & data, const std::string & salt) std::string HashedCredDB::Hash(const std::string & data, const std::string & salt)
{ {
SHA512Digest h; SHA512Digest h;
@ -57,5 +66,33 @@ namespace nntpchan
SHA512((const uint8_t*)d.c_str(), d.size(), h); SHA512((const uint8_t*)d.c_str(), d.size(), h);
return B64Encode(h.data(), h.size()); return B64Encode(h.data(), h.size());
} }
HashedFileDB::HashedFileDB(const std::string & fname) :
m_fname(fname),
f(nullptr)
{
}
HashedFileDB::~HashedFileDB()
{
}
void HashedFileDB::Close()
{
if(f.is_open())
f.close();
}
bool HashedFileDB::Open()
{
if(!f.is_open())
f.open(m_fname);
if(f.is_open()) {
SetStream(&f);
return true;
}
return false;
}
} }

View File

@ -2,6 +2,7 @@
#define NNTPCHAN_NNTP_AUTH_HPP #define NNTPCHAN_NNTP_AUTH_HPP
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <fstream>
#include <mutex> #include <mutex>
#include "line.hpp" #include "line.hpp"
@ -11,27 +12,45 @@ namespace nntpchan
class NNTPCredentialDB class NNTPCredentialDB
{ {
public: public:
/** @brief open connection to database, return false on error otherwise return true */
virtual bool Open() = 0;
/** @brief close connection to database */
virtual void Close() = 0;
/** @brief return true if username password combo is correct */ /** @brief return true if username password combo is correct */
virtual bool CheckLogin(const std::string & user, const std::string & passwd) = 0; virtual bool CheckLogin(const std::string & user, const std::string & passwd) = 0;
virtual ~NNTPCredentialDB() {}
}; };
/** @brief nntp credential db using hashed+salted passwords */ /** @brief nntp credential db using hashed+salted passwords */
class HashedCredDB : public NNTPCredentialDB, public LineReader class HashedCredDB : public NNTPCredentialDB, public LineReader
{ {
public: public:
HashedCredDB(std::istream & i);
bool CheckLogin(const std::string & user, const std::string & passwd); bool CheckLogin(const std::string & user, const std::string & passwd);
protected: protected:
std::string Hash(const std::string & data, const std::string & salt); void SetStream(std::istream * i);
private:
std::string Hash(const std::string & data, const std::string & salt);
void HandleLine(const std::string & line);
private:
bool ProcessLine(const std::string & line); bool ProcessLine(const std::string & line);
std::mutex m_access; std::mutex m_access;
std::string m_user, m_passwd; std::string m_user, m_passwd;
bool m_found; bool m_found;
/** return true if we have a line that matches this username / password combo */ /** return true if we have a line that matches this username / password combo */
std::istream & m_instream; std::istream * m_instream;
};
class HashedFileDB : public HashedCredDB
{
public:
HashedFileDB(const std::string & fname);
~HashedFileDB();
bool Open();
void Close();
private:
std::string m_fname;
std::ifstream f;
}; };
} }

View File

@ -8,12 +8,18 @@
namespace nntpchan namespace nntpchan
{ {
NNTPServerHandler::NNTPServerHandler(const std::string & storage) : NNTPServerHandler::NNTPServerHandler(const std::string & storage) :
m_auth(nullptr),
m_store(storage), m_store(storage),
m_authed(false), m_authed(false),
m_state(eStateReadCommand) m_state(eStateReadCommand)
{ {
} }
NNTPServerHandler::~NNTPServerHandler()
{
if(m_auth) delete m_auth;
}
void NNTPServerHandler::HandleLine(const std::string &line) void NNTPServerHandler::HandleLine(const std::string &line)
{ {
if(m_state == eStateReadCommand) { if(m_state == eStateReadCommand) {
@ -58,6 +64,7 @@ namespace nntpchan
void NNTPServerHandler::SwitchMode(const std::string & mode) void NNTPServerHandler::SwitchMode(const std::string & mode)
{ {
} }
void NNTPServerHandler::Quit() void NNTPServerHandler::Quit()
@ -71,4 +78,23 @@ namespace nntpchan
{ {
return m_state == eStateQuit; return m_state == eStateQuit;
} }
bool NNTPServerHandler::PostingAllowed()
{
return m_authed || m_auth == nullptr;
}
void NNTPServerHandler::Greet()
{
if(PostingAllowed())
QueueLine("200 Posting allowed");
else
QueueLine("201 Posting not allowed");
}
void NNTPServerHandler::SetAuth(NNTPCredentialDB *creds)
{
if(m_auth) delete m_auth;
m_auth = creds;
}
} }

View File

@ -3,6 +3,7 @@
#include <deque> #include <deque>
#include <string> #include <string>
#include "line.hpp" #include "line.hpp"
#include "nntp_auth.hpp"
#include "storage.hpp" #include "storage.hpp"
namespace nntpchan namespace nntpchan
@ -11,9 +12,14 @@ namespace nntpchan
{ {
public: public:
NNTPServerHandler(const std::string & storage); NNTPServerHandler(const std::string & storage);
~NNTPServerHandler();
bool Done(); bool Done();
void SetAuth(NNTPCredentialDB * creds);
void Greet();
protected: protected:
void HandleLine(const std::string & line); void HandleLine(const std::string & line);
void HandleCommand(const std::deque<std::string> & command); void HandleCommand(const std::deque<std::string> & command);
@ -32,8 +38,10 @@ namespace nntpchan
// switch nntp modes, this queues a reply // switch nntp modes, this queues a reply
void SwitchMode(const std::string & mode); void SwitchMode(const std::string & mode);
private: bool PostingAllowed();
private:
NNTPCredentialDB * m_auth;
ArticleStorage m_store; ArticleStorage m_store;
std::string m_mode; std::string m_mode;
bool m_authed; bool m_authed;

View File

@ -1,5 +1,6 @@
#include "buffer.hpp" #include "buffer.hpp"
#include "nntp_server.hpp" #include "nntp_server.hpp"
#include "nntp_auth.hpp"
#include "net.hpp" #include "net.hpp"
#include <cassert> #include <cassert>
#include <iostream> #include <iostream>
@ -38,19 +39,32 @@ namespace nntpchan
std::cerr << "nntp server OnAccept fail: " << uv_strerror(status) << std::endl; std::cerr << "nntp server OnAccept fail: " << uv_strerror(status) << std::endl;
return; return;
} }
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath); NNTPCredentialDB * creds = nullptr;
std::ifstream i;
i.open(m_logindbpath);
if(i.is_open()) creds = new HashedFileDB(m_logindbpath);
NNTPServerConn * conn = new NNTPServerConn(m_loop, s, m_storagePath, creds);
conn->Greet(); conn->Greet();
} }
void NNTPServer::SetLoginDB(const std::string path)
{
m_logindbpath = path;
}
void NNTPServer::SetStoragePath(const std::string & path) void NNTPServer::SetStoragePath(const std::string & path)
{ {
m_storagePath = path; m_storagePath = path;
} }
NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage) : NNTPServerConn::NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds) :
m_handler(storage) m_handler(storage)
{ {
m_handler.SetAuth(creds);
uv_tcp_init(l, &m_conn); uv_tcp_init(l, &m_conn);
m_conn.data = this; m_conn.data = this;
uv_accept(s, (uv_stream_t*) &m_conn); uv_accept(s, (uv_stream_t*) &m_conn);
@ -93,7 +107,8 @@ namespace nntpchan
void NNTPServerConn::Greet() void NNTPServerConn::Greet()
{ {
m_handler.Greet();
SendNextReply();
} }
void NNTPServerConn::SendString(const std::string & str) void NNTPServerConn::SendString(const std::string & str)

View File

@ -24,6 +24,8 @@ namespace nntpchan
void SetStoragePath(const std::string & path); void SetStoragePath(const std::string & path);
void SetLoginDB(const std::string path);
private: private:
operator uv_handle_t * () { return (uv_handle_t*) &m_server; } operator uv_handle_t * () { return (uv_handle_t*) &m_server; }
@ -35,6 +37,7 @@ namespace nntpchan
std::deque<NNTPServerConn *> m_conns; std::deque<NNTPServerConn *> m_conns;
std::string m_logindbpath;
std::string m_storagePath; std::string m_storagePath;
}; };
@ -42,8 +45,7 @@ namespace nntpchan
class NNTPServerConn class NNTPServerConn
{ {
public: public:
NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage); NNTPServerConn(uv_loop_t * l, uv_stream_t * s, const std::string & storage, NNTPCredentialDB * creds);
/** @brief close connection, this connection cannot be used after calling this */ /** @brief close connection, this connection cannot be used after calling this */
void Close(); void Close();
@ -63,8 +65,6 @@ namespace nntpchan
NNTPServerHandler m_handler; NNTPServerHandler m_handler;
NNTPCredentialDB * m_logindb;
char m_readbuff[1028]; char m_readbuff[1028];
}; };

View File

@ -1,18 +1,91 @@
#include "base64.hpp" #include "base64.hpp"
#include "crypto.hpp" #include "crypto.hpp"
#include <cassert>
#include <cstring>
#include <string> #include <string>
#include <iostream> #include <iostream>
#include <sodium.h>
static void print_help(const std::string & exename) static void print_help(const std::string & exename)
{ {
std::cout << "usage: " << exename << " [help|passwd|genconf]" << std::endl; std::cout << "usage: " << exename << " [help|gencred|checkcred]" << std::endl;
}
static void print_long_help() {
}
static void gen_passwd(const std::string & username, const std::string & passwd)
{
std::array<uint8_t, 8> random;
randombytes_buf(random.data(), random.size());
std::string salt = nntpchan::B64Encode(random.data(), random.size());
std::string cred = passwd + salt;
nntpchan::SHA512Digest d;
nntpchan::SHA512((const uint8_t *)cred.c_str(), cred.size(), d);
std::string hash = nntpchan::B64Encode(d.data(), d.size());
std::cout << username << ":" << hash << ":" << salt << std::endl;
}
static bool check_cred(const std::string & cred, const std::string & passwd)
{
auto idx = cred.find(":");
if(idx == std::string::npos || idx == 0) return false;
std::string part = cred.substr(idx+1);
idx = part.find(":");
if(idx == std::string::npos || idx == 0) return false;
std::string salt = part.substr(idx+1);
std::string hash = part.substr(0, idx);
std::vector<uint8_t> h;
if(!nntpchan::B64Decode(hash, h)) return false;
nntpchan::SHA512Digest d;
std::string l = passwd + salt;
nntpchan::SHA512((const uint8_t*)l.data(), l.size(), d);
return std::memcmp(h.data(), d.data(), d.size()) == 0;
} }
int main(int argc, char * argv[]) int main(int argc, char * argv[])
{ {
assert(sodium_init() == 0);
if(argc == 1) { if(argc == 1) {
print_help(argv[0]); print_help(argv[0]);
return 1; return 1;
} }
std::string cmd(argv[1]);
if (cmd == "help") {
print_long_help();
return 0;
}
if (cmd == "gencred") {
if(argc == 4) {
gen_passwd(argv[2], argv[3]);
return 0;
} else {
std::cout << "usage: " << argv[0] << " passwd username password" << std::endl;
return 1;
}
}
if(cmd == "checkcred" ) {
std::string cred;
std::cout << "credential: " ;
if(!std::getline(std::cin, cred)) {
return 1;
}
std::string passwd;
std::cout << "password: ";
if(!std::getline(std::cin, passwd)) {
return 1;
}
if(check_cred(cred, passwd)) {
std::cout << "okay" << std::endl;
return 0;
}
std::cout << "bad login" << std::endl;
return 1;
}
print_help(argv[0]);
return 1;
} }