Skip to content
authdb.cpp 54.7 KiB
Newer Older
jan.koester's avatar
jan.koester committed
            AuthBackend *backend=nullptr;

            if(strcmp(cdid,"admin")!=0){
                if(uuid_parse(cdid,did)<0)
                    throw AuthBackendError("createGroups: wrong domain id !");
                backend=dbackend.data(did);
            }else{
                backend=&_AdminBackend;
            }

            if(!backend)
                throw AuthBackendError("createGroups: no backend seleted!");

            libhttppp::HttpForm curform;
            curform.parse(curreq);

            if (curform.getBoundary()) {
                size_t gcount=0;
                std::string gname;

                uuid_t gid;
                uuid_generate(gid);

                class GroupData grp(gid);

                for (libhttppp::HttpForm::MultipartForm::Data* curformdat = curform.MultipartFormData.getFormData();
                     curformdat; curformdat = curformdat->nextData()) {

                    if(curformdat->Value.empty())
                        continue;


                    for(libhttppp::HttpForm::MultipartForm::Data::ContentDisposition *curdispo=curformdat->getDisposition();
                        curdispo; curdispo=curdispo->nextContentDisposition()
                    ){
                        std::string tmp=curdispo->getKey();

                        std::transform(tmp.begin(), tmp.end(), tmp.begin(),
                                       [](unsigned char c){ return std::tolower(c); });

                        if(tmp=="name" && strcmp(curdispo->getValue(),"members")==0){
                            ++gcount;
                        }

                        if(tmp=="name" && strcmp(curdispo->getValue(),"groupname")==0){
                            std::copy(curformdat->Value.begin(),curformdat->Value.end(),std::back_inserter(gname));
                        }

                    }
                }

                if(gname.empty())
                    throw AuthBackendError("createGroups: no doamin name given");

                grp.Members->count=gcount;
                grp.Members->uid = new uuid_t[gcount];
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                size_t git=0;
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
                for (libhttppp::HttpForm::MultipartForm::Data* curformdat = curform.MultipartFormData.getFormData();
                     curformdat; curformdat = curformdat->nextData()) {

                    for(libhttppp::HttpForm::MultipartForm::Data::ContentDisposition *curdispo=curformdat->getDisposition();
                        curdispo; curdispo=curdispo->nextContentDisposition()
                    ){
                        std::string tmp=curdispo->getKey();

                        std::transform(tmp.begin(), tmp.end(), tmp.begin(),
                                       [](unsigned char c){ return std::tolower(c); });

                        if(tmp=="name" && strcmp(curdispo->getValue(),"members")==0){
                            uuid_parse(curformdat->Value.data(),grp.Members->uid[git]);
                            ++git;
                        }
                    }

                }

                delete[] grp.Members->uid;
            }

            size_t rd=sizeof(authdb::AuthHeader),end=backend->end();

            form  << "<form method=\"post\" enctype=\"multipart/form-data\">"
                  << "<table>"
                  << "<tr><th>Create Group:</th></tr>"
                  << "<tr><td><label for=\"groupname\">groupname:</label></td>"
                  << "<td><input type=\"text\" name=\"groupname\"></td></tr>"
                  << "<tr><td>Members:</td>"
                  << "<td><select name=\"members\" multiple>";
            while(rd<end){
                authdb::AuthData::Record cur;

                cur.type=EmptyData;

                backend->setPos(rd);
                backend->read((unsigned char*)&cur,sizeof(AuthData::Record));

                rd=backend->getPos()+cur.datasize;

                if(cur.type == UserData && strcmp(cur.fieldname,"username")==0){
                    cur.data=new char[cur.datasize];
                    backend->read((unsigned char*)cur.data,cur.datasize);
                    char cuid[255];
                    uuid_unparse(cur.uuid,cuid);
                    form << "<option value=\"" << cuid << "\">" << cur.data << "</option>";
                    delete[] cur.data;
                }

            }
            form  << "</select></td></tr>"
                  << "<tr><td></td><td><input type=\"submit\" value=\"Create group\"></td></tr>"
                  << "</table>"
                  << "</form";

            content->appendChild(form.parse());

            libhtmlpp::print(&root,out,true);

            libhttppp::HttpResponse rep;
            rep.setContentType("text/html");
            rep.setContentLength(out.size());
            rep.send(curreq,out.c_str(),out.size());
jan.koester's avatar
jan.koester committed
        }

jan.koester's avatar
jan.koester committed
        void SettingsController(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
jan.koester's avatar
jan.koester committed
            _AdminBackend.lock();

            char domain[255],url[255];

jan.koester's avatar
jan.koester committed
            if(sscanf(curreq->getRequestURL(),"/settings/%[^/]/%s",domain,url)<0)
jan.koester's avatar
jan.koester committed
                throw AuthBackendError("wrong url!");

jan.koester's avatar
jan.koester committed
            try {
jan.koester's avatar
jan.koester committed
                if(strncmp(url,"listusers",9)==0){
jan.koester's avatar
jan.koester committed
                    listUsers(curreq,tid,args,"listusers");
jan.koester's avatar
jan.koester committed
                }else if(strncmp(url,"createuser",9)==0){
jan.koester's avatar
jan.koester committed
                    createUser(curreq,tid,args,"createuser");
jan.koester's avatar
jan.koester committed
                }else if(strncmp(url,"removeuser",9)==0){
jan.koester's avatar
jan.koester committed
                    removeuser(curreq,tid,args);
jan.koester's avatar
jan.koester committed
                }else if(strncmp(url,"edituser",8)==0){
jan.koester's avatar
jan.koester committed
                    editUser(curreq,tid,args);
jan.koester's avatar
jan.koester committed
                }else if(strncmp(url,"listdomains",9)==0){
jan.koester's avatar
jan.koester committed
                    listDomains(curreq,tid,args);
jan.koester's avatar
jan.koester committed
                }else if(strncmp(url,"createdomain",12)==0){
jan.koester's avatar
jan.koester committed
                    createDomain(curreq,tid,args);
jan.koester's avatar
jan.koester committed
                }else if(strncmp(url,"removedomain",12)==0){
jan.koester's avatar
jan.koester committed
                    removeDomain(curreq,tid,args);
jan.koester's avatar
jan.koester committed
                }else if(strncmp(url,"listgroups",10)==0){
                    listGroups(curreq,tid,args,"listgroups");
                }else if(strncmp(url,"creategroup",11)==0){
                    createGroup(curreq,tid,args,"creategroup");
jan.koester's avatar
jan.koester committed
                }else{
                    libhtmlpp::HtmlElement root=_IndexElement;
                    libhtmlpp::HtmlString out;
                    libhtmlpp::print(&root,out,true);

                    libhttppp::HttpResponse rep;
                    rep.setContentType("text/html");
                    rep.setContentLength(out.size());
                    rep.send(curreq,out.c_str(),out.size());
                }
            }catch(AuthBackendError &e){
                    libhttppp::HttpResponse rep;
                    rep.setState(HTTP500);
                    rep.setContentType("text/html");
                    rep.send(curreq,e.what(),strlen(e.what()));
jan.koester's avatar
jan.koester committed
            }
jan.koester's avatar
jan.koester committed
            _AdminBackend.unlock();
jan.koester's avatar
jan.koester committed
        }

        void RequestEvent(libhttppp::HttpRequest *curreq, const int tid, ULONG_PTR args){
jan.koester's avatar
jan.koester committed
            if(strncmp(curreq->getRequestURL(),"/settings",9)==0){
                SettingsController(curreq,tid,args);
            }if(strncmp(curreq->getRequestURL(),"/getavatar/",11)==0){
                getAvatar(curreq,tid,args);
jan.koester's avatar
jan.koester committed
            }else if(strncmp(curreq->getRequestURL(),"/api",4)==0){

jan.koester's avatar
jan.koester committed
            }else if(strncmp(curreq->getRequestURL(),"/authdb.js",10)==0){
                libhttppp::HttpResponse rep;
                rep.setContentType("text/javascript");
                rep.send(curreq,_AuthJs.data(),_AuthJs.size());
jan.koester's avatar
jan.koester committed
            }else{
                libhttppp::HttpResponse rep;
                rep.setState(HTTP307);
                rep.setVersion(HTTPVERSION(1.1));
jan.koester's avatar
jan.koester committed
                rep.setHeaderData("Location")->push_back("/settings/admin/index");
jan.koester's avatar
jan.koester committed
                rep.setContentType("text/html");
                rep.send(curreq,nullptr,0);
jan.koester's avatar
jan.koester committed
            }
jan.koester's avatar
jan.koester committed
        };
    private:
jan.koester's avatar
jan.koester committed
        authdb::AuthBackend     _AdminBackend;
jan.koester's avatar
jan.koester committed
        libhtmlpp::HtmlElement  _IndexElement;
        libhtmlpp::HtmlPage     _Indexpage;
jan.koester's avatar
jan.koester committed
        std::vector<char>       _AuthJs;
jan.koester's avatar
jan.koester committed
    };

    int searchValue(authdb::AuthBackend &backend,const char*fieldname,const char *value){
jan.koester's avatar
jan.koester committed
        authdb::AuthData::Record *user=new AuthData::Record;
jan.koester's avatar
jan.koester committed
        int rd=sizeof(authdb::AuthHeader),brd=rd;
        while(rd>backend.end()){
jan.koester's avatar
jan.koester committed
            backend.setPos(rd);
            backend.read((unsigned char*)user,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
            rd=backend.getPos();
jan.koester's avatar
jan.koester committed
            if(strcmp(user->fieldname,fieldname) == 0){
jan.koester's avatar
jan.koester committed
                user->data = new char[user->datasize];
                backend.read((unsigned char*)user->data,user->datasize);
jan.koester's avatar
jan.koester committed
                if(strcmp(user->data,value) == 0){
                    delete[] user->data;
jan.koester's avatar
jan.koester committed
                    goto VALUEFOUND;
jan.koester's avatar
jan.koester committed
                }
jan.koester's avatar
jan.koester committed
                delete[] user->data;
jan.koester's avatar
jan.koester committed
            }
            brd=rd;
        }
jan.koester's avatar
jan.koester committed
VALUEFOUND:
jan.koester's avatar
jan.koester committed
        delete user;
jan.koester's avatar
jan.koester committed
        return brd;
    AuthData::AuthData(const uuid_t id){
jan.koester's avatar
jan.koester committed
         Data = new struct AuthData::Record;
jan.koester's avatar
jan.koester committed
         memset(Data,0,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
         uuid_copy(Data->uuid,id);
jan.koester's avatar
jan.koester committed
         Data->start=0xFE;
         Data->storage=EmptyStorage;
jan.koester's avatar
jan.koester committed
         Data->type=DataType::EmptyData;
         Data->fieldname[0]='\0';
         Data->data=nullptr;
         Data->datasize=0;
jan.koester's avatar
jan.koester committed
        _next=nullptr;
    }

jan.koester's avatar
jan.koester committed
    AuthData::AuthData(const AuthData &src) :AuthData(src.Data->uuid){
        AuthData *dest=this;

        for(const AuthData *cursrc=&src; cursrc; cursrc=cursrc->next()){
            memcpy(dest->Data,cursrc->Data,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
            dest->Data->datasize=cursrc->Data->datasize;
            dest->Data->data=new char[dest->Data->datasize];
            memcpy(dest->Data->data,cursrc->Data->data,cursrc->Data->datasize);
            if(cursrc->next()){
jan.koester's avatar
jan.koester committed
                dest->_next=new AuthData(cursrc->Data->uuid);
                dest=dest->_next;
            }
        }
jan.koester's avatar
jan.koester committed
    AuthData::~AuthData(){
jan.koester's avatar
jan.koester committed
        delete Data;
jan.koester's avatar
jan.koester committed
    AuthData *AuthData::next() const{
jan.koester's avatar
jan.koester committed
        return _next;
jan.koester's avatar
jan.koester committed
    bool authdb::AuthData::empty(){
        if(!Data->data)
            return true;
        return false;
    };

jan.koester's avatar
jan.koester committed
    AuthData *AuthData::append(const AuthData &src){
jan.koester's avatar
jan.koester committed
        AuthData *curec=this,*next=this;
        if(!curec->_next && curec->Data->datasize==0){
            for(const AuthData *cursrc=&src; cursrc; cursrc=cursrc->next()){
                next->append(*src.Data);
                if(cursrc->next()){
                    next->_next=new AuthData(Data->uuid);
                    next=next->_next;
                }
            }
            return curec;
        }
jan.koester's avatar
jan.koester committed
        while(curec){
jan.koester's avatar
jan.koester committed
            if(!curec->_next){
jan.koester's avatar
jan.koester committed
                curec->_next=new AuthData(src);
jan.koester's avatar
jan.koester committed
                curec=curec->_next;
                break;
            }
            curec=curec->_next;
jan.koester's avatar
jan.koester committed
        };
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        return curec;
    }

    AuthData *AuthData::append(const AuthData::Record &src){
        AuthData *curec=this;
jan.koester's avatar
jan.koester committed
        if(!curec->_next && curec->Data->datasize==0){
            memcpy(curec->Data,&src,sizeof(AuthData::Record));
            curec->Data->data=new char[curec->Data->datasize];
            memcpy(curec->Data->data,src.data,curec->Data->datasize);
            return curec;
        }

        while(curec){
jan.koester's avatar
jan.koester committed
            if(!curec->_next){
                curec->_next=new AuthData(Data->uuid);
jan.koester's avatar
jan.koester committed
                curec=curec->_next;
jan.koester's avatar
jan.koester committed
                curec->append(src);
jan.koester's avatar
jan.koester committed
                break;
            }
            curec=curec->_next;
jan.koester's avatar
jan.koester committed
        };
jan.koester's avatar
jan.koester committed

        return curec;
    }

    bool getRecord(authdb::AuthBackend &backend,AuthData &rec,int type){
jan.koester's avatar
jan.koester committed
        bool found=false;
        int rd=sizeof(authdb::AuthHeader),end=backend.end();
jan.koester's avatar
jan.koester committed
        AuthData *curec=&rec;
jan.koester's avatar
jan.koester committed

        while(rd<end){
            AuthData::Record cur;
            memset(&cur,0,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
            backend.setPos(rd);
            backend.read((unsigned char*)&cur,sizeof(AuthData::Record));
            rd=backend.getPos()+cur.datasize;
            if(uuid_compare(cur.uuid,rec.Data->uuid) == 0 && cur.type == type){
                cur.data=new char[cur.datasize];
                backend.read((unsigned char*)cur.data,cur.datasize);
                rec.append(cur);
                delete[] cur.data;
jan.koester's avatar
jan.koester committed
                found=true;
jan.koester's avatar
jan.koester committed

jan.koester's avatar
jan.koester committed
        return found;
    }
    bool editRecord(AuthBackend &backend,AuthData &rec,int type){
        AuthData old(rec.Data->uuid);
jan.koester's avatar
jan.koester committed
        std::vector<AuthData::Record*> changemap; //use fieldname;
        std::vector<AuthData::Record*> newmap;
        getRecord(backend,old,type);
jan.koester's avatar
jan.koester committed
        for(const AuthData *curdat=&rec; curdat; curdat=curdat->_next){
jan.koester's avatar
jan.koester committed
            bool newentry=true;
jan.koester's avatar
jan.koester committed
            if(rec.Data->datasize==0)
                continue;

jan.koester's avatar
jan.koester committed
            for(const AuthData *olddat=&old; olddat; olddat=olddat->_next){
                if(uuid_compare(olddat->Data->uuid,curdat->Data->uuid)==0
jan.koester's avatar
jan.koester committed
                    && strcmp(olddat->Data->fieldname,curdat->Data->fieldname)==0
                ){
                    size_t end = olddat->Data->datasize;
                    if(end!=curdat->Data->datasize){
                        changemap.push_back(curdat->Data);
                    }else{
                        for(size_t i=0; i<end; ++i){
                            if(olddat->Data->data[i]!=curdat->Data->data[i]){
                                changemap.push_back(curdat->Data);
                                break;
                            }
                        }
                    }
                    newentry=false;
                }
            }

            if(newentry){
                newmap.push_back(curdat->Data);
            }

        }

        for(auto newel : newmap){
            backend.setPos(backend.end());
jan.koester's avatar
jan.koester committed
            backend.write((unsigned char*)newel,sizeof(AuthData::Record));;
            backend.write((unsigned char*)newel->data,newel->datasize);
jan.koester's avatar
jan.koester committed
        }

        const unsigned char zero = 0;


        for(auto chel : changemap){
            size_t rd=sizeof(authdb::AuthHeader),end=backend.end();
            while(rd<end){
jan.koester's avatar
jan.koester committed
                authdb::AuthData::Record *rdrec=new AuthData::Record;
                backend.setPos(rd);
                backend.read((unsigned char*)rdrec,sizeof(AuthData::Record));
                if(uuid_compare(rdrec->uuid,rec.Data->uuid)==0 && strcmp(rdrec->fieldname,chel->fieldname)==0){
jan.koester's avatar
jan.koester committed
                    backend.setPos(backend.end());
                    backend.write((const unsigned char*)chel,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                    backend.write((const unsigned char*)chel->data,chel->datasize);
                    size_t dsize=rdrec->datasize;
jan.koester's avatar
jan.koester committed
                    memset(rdrec,0,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                    rdrec->start = 0xFE;
jan.koester's avatar
jan.koester committed
                    rdrec->datasize=dsize;
jan.koester's avatar
jan.koester committed
                    backend.setPos(rd);
                    backend.write((const unsigned char*)rdrec,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                    for(size_t i =0; i<rdrec->datasize; ++i){
                        backend.write(&zero,1);
                    }
                    rd=backend.getPos();
                }else{
                    rd=backend.getPos()+rdrec->datasize;
                }
                delete rdrec;
            }
        }

        if(!changemap.empty() || !newmap.empty())
            return true;
        return false;
    }

jan.koester's avatar
jan.koester committed
    void delRecord(AuthBackend &backend,const uuid_t uid,int type){
jan.koester's avatar
jan.koester committed
        size_t end=backend.end(),rd=sizeof(AuthHeader);

        if(!uid)
            throw AuthBackendError("user info uid required!");

        while(rd<end){
jan.koester's avatar
jan.koester committed
            authdb::AuthData::Record *cur=new AuthData::Record;
            backend.setPos(rd);
            size_t wr=backend.getPos();
jan.koester's avatar
jan.koester committed
            backend.read((unsigned char*)cur,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
            rd=backend.getPos()+cur->datasize;
jan.koester's avatar
jan.koester committed
            if(uuid_compare(uid,cur->uuid) == 0 && type == cur->type){
jan.koester's avatar
jan.koester committed
                size_t dsize=cur->datasize;
                memset(cur,0,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                cur->start = 0xFE;
jan.koester's avatar
jan.koester committed
                cur->datasize=dsize;
jan.koester's avatar
jan.koester committed
                backend.setPos(wr);
                backend.write((unsigned char*)cur,sizeof(AuthData::Record));
jan.koester's avatar
jan.koester committed
                const unsigned char zero=0;
                for(size_t i=0; i<dsize; ++i){
                    backend.write(&zero,1);
                }
            }
            delete cur;
        }
    }

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)){
jan.koester's avatar
jan.koester committed
            authdb::initalized=false;
jan.koester's avatar
jan.koester committed
        }

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
}