Skip to content
authdb.cpp 8.69 KiB
Newer Older
jan.koester's avatar
jan.koester committed
/*******************************************************************************
jan.koester's avatar
jan.koester committed
 * Copyright (c) 2025, Jan Koester jan.koester@gmx.net
jan.koester's avatar
jan.koester committed
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * Redistributions of source code must retain the above copyright
 *      notice, this list of conditions and the following disclaimer.
 * Redistributions in binary form must reproduce the above copyright
 *      notice, this list of conditions and the following disclaimer in the
 *      documentation and/or other materials provided with the distribution.
 * Neither the name of the <organization> nor the
 *      names of its contributors may be used to endorse or promote products
 *      derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *******************************************************************************/

#include <iostream>
jan.koester's avatar
jan.koester committed
#include <cstring>
jan.koester's avatar
jan.koester committed
#include <sstream>
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
#include <uuid/uuid.h>
jan.koester's avatar
jan.koester committed
#include <cmdplus/cmdplus.h>
#include <confplus/conf.h>
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
#include <httppp/httpd.h>

jan.koester's avatar
jan.koester committed
#include "backend.h"
jan.koester's avatar
jan.koester committed
#include "authdb.h"
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
namespace authdb {
    class AuthDB : public libhttppp::HttpEvent{
    public:
        AuthDB(authdb::AuthBackend &backend,netplus::socket *ssock) : HttpEvent(ssock), _Backend(backend){

        };

        void RequestEvent(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
                _Backend.lock();

                authdb::AuthData cur;

                size_t rd=sizeof(authdb::AuthHeader),end=_Backend.end();

                _Backend.setPos(rd);

                std::string userlist="UserList:\r\n";

                while(rd<end){
                    _Backend.ReadAuthData(cur,rd);
                    rd=_Backend.getPos();
                    if(strcmp(cur.fieldname,"username")==0){
                        AuthDataRecord rec;
                        uuid_t uid;
                        uuid_parse(cur.uuid,uid);
                        _Backend.setPos(sizeof(AuthHeader));
                        getRecord(_Backend,&rec,uid,1);
                        userlist+="User: ";
                        userlist+= cur.data;
                        userlist+=" UID: ";
                        userlist+= cur.uuid;
                        userlist+= "\r\n";
                        for(AuthDataRecord *curec=&rec; curec; curec=curec->next()){
                            if(strcmp(curec->Data.fieldname,"username")!=0){
                                userlist+="  ";
                                userlist+=curec->Data.fieldname;
                                userlist+=": ";
                                std::copy(curec->Data.data,curec->Data.data+curec->Data.datasize,
                                          std::back_inserter(userlist));
                                userlist+= "\r\n";
                            }
                        }
                    }
                }

                _Backend.unlock();

                libhttppp::HttpResponse rep;
                rep.setContentType("text/txt");
                rep.setContentLength(userlist.length());
                rep.send(curreq,userlist.c_str(),userlist.length());
        };
    private:
        authdb::AuthBackend &_Backend;
    };

    int searchValue(authdb::AuthBackend &backend,const char*fieldname,const char *value){
        authdb::AuthData user,attr;
        int rd=sizeof(authdb::AuthHeader),brd=rd;
        while(rd>backend.end()){
            backend.ReadAuthData(user,rd);
            rd=backend.getPos();
            if(strcmp(user.fieldname,fieldname) == 0){
                if(strcmp(user.data,value) == 0){
                    delete[] user.data;
                    return brd;
                }
            }
            brd=rd;
            delete[] user.data;
        }
        return -1;
    }

    AuthDataRecord::AuthDataRecord(){
        _next=nullptr;
    }

    AuthDataRecord::AuthDataRecord(const AuthDataRecord &src){
        memcpy(&Data,&src.Data,sizeof(src.Data));
        memcpy(Data.data,src.Data.data,src.Data.datasize);
        _next=nullptr;
    }

    AuthDataRecord::~AuthDataRecord(){

    }

    AuthDataRecord *AuthDataRecord::next(){
            return _next;
    };


    bool getRecord(authdb::AuthBackend &backend,AuthDataRecord *dest,uuid_t id,int type){
        bool found=false;
        authdb::AuthData cur;
        int rd=sizeof(authdb::AuthHeader),end=backend.end();

        char plainid[255];

        uuid_unparse(id,plainid);

        AuthDataRecord *curec=dest;

        while(rd<end){
            backend.ReadAuthData(cur,rd);
            rd=backend.getPos();
            if( strcmp(cur.uuid,plainid) == 0 && cur.type == type){
                memcpy(&curec->Data,&cur,sizeof(AuthData));
                curec->Data.data=new char(cur.datasize);
                memcpy(curec->Data.data,cur.data,cur.datasize);
                if(rd<backend.end()){
                    curec->_next=new AuthDataRecord;
                    curec=curec->_next;
                }
                found=true;
            }
            delete[] cur.data;
        }
        return found;
    }
};

jan.koester's avatar
jan.koester committed
int main(int argc, char *argv[]){
    cmdplus::CmdController &cmd=cmdplus::CmdController::getInstance();
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
    cmd.registerCmd("config",'c',true,nullptr,"Config Path");
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
    cmd.parseCmd(argc,argv);
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
    if(!cmd.checkRequired()){
        std::cerr << "Config Path required !" << std::endl;
        cmd.printHelp();
        return -1;
    }

    confplus::Config config(cmd.getCmdbyKey("config")->getValue());

    authdb::AuthBackend backend(authdb::AuthBackendType::File,
                                config.getValue(config.getKey("/AUTHDB/ADMINDB/PATH"),0),
                                "admin.local"
                                );
jan.koester's avatar
jan.koester committed
    try {
jan.koester's avatar
jan.koester committed
        if(backend.end()<=sizeof(authdb::AuthHeader)){
                std::string username,password;
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                std::cerr << "Initial User not found !" << std::endl;
                std::cout << "Please Enter Username: ";
                std::cin >> username;
                std::cout << "Please Enter Password: ";
                std::cin >> password;

                std::cout << "Creating User !";

                authdb::AuthData user,pw;
jan.koester's avatar
jan.koester committed

                uuid_t id;
                uuid_generate(id);

                uuid_unparse(id,user.uuid);
jan.koester's avatar
jan.koester committed
                uuid_unparse(id,pw.uuid);
jan.koester's avatar
jan.koester committed

                user.type=1;
jan.koester's avatar
jan.koester committed
                snprintf(user.fieldname,255,"%s","username");

                pw.type=1;
                snprintf(pw.fieldname,255,"%s","password");

                user.datasize=username.length()+1;
                user.data = new char[user.datasize];
                snprintf(user.data,user.datasize,"%s",username.c_str());

jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                pw.datasize=password.length()+1;
                pw.data = new char[pw.datasize];
                snprintf(pw.data,pw.datasize,"%s",password.c_str());
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                authdb::AuthData euser;
                int rd=sizeof(authdb::AuthHeader);
                while(rd<backend.end()){
jan.koester's avatar
jan.koester committed
                    backend.ReadAuthData(euser,rd);
jan.koester's avatar
jan.koester committed
                    rd=backend.getPos();
                    if(strcmp(euser.fieldname,"username") == 0 && strcmp(euser.data,user.data)==0 ){
                        delete[] euser.data;
                        throw authdb::AuthBackendError("Username already exits");
                    }
                    delete[] euser.data;
                }

jan.koester's avatar
jan.koester committed
                backend.WriteAuthData(user,backend.end());
                backend.WriteAuthData(pw,backend.end());
        }

jan.koester's avatar
jan.koester committed
        libhttppp::HttpD httpd(
            config.getValue(config.getKey("/AUTHDB/BIND"),0),
            config.getIntValue(config.getKey("/AUTHDB/PORT"),0),
            config.getIntValue(config.getKey("/AUTHDB/MAXCONN"),0),
            nullptr,
            nullptr
        );
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        authdb::AuthDB authdb(backend,httpd.getServerSocket());
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        authdb.runEventloop();
jan.koester's avatar
jan.koester committed
    }catch(authdb::AuthBackendError &e){
        std::cerr << e.what() << std::endl;
    }
jan.koester's avatar
jan.koester committed
}