hs.hsadmin/hsacppcli/hsadminc/source/configfile.cpp

258 lines
7.3 KiB
C++
Raw Permalink Normal View History

/***************************************************************************
* Copyright (C) 2005 by Christof Donat *
* cdonat@gmx.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include "configfile.h"
#include "logger.h"
#include <boost/filesystem/exception.hpp>
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
#include <errno.h>
#include <assert.h>
using std::ostringstream;
using std::istringstream;
using std::ifstream;
using std::fstream;
using std::string;
using boost::lexical_cast;
using boost::bad_lexical_cast;
ConfigFileFinder::ConfigFileFinder(Transaction& t): vector<string*>() {
try {
boost::filesystem::path general("/etc/hsadminc.conf");
if( boost::filesystem::exists(general) && !boost::filesystem::is_directory(general) )
this->loadFile(general.native());
} catch(boost::filesystem::filesystem_error) {}
string priv = getenv("HOME");
try {
boost::filesystem::path p( priv + "/.hsadmin.conf");
if( boost::filesystem::exists(p) && !boost::filesystem::is_directory(p) )
this->loadFile(p.native());
} catch(boost::filesystem::filesystem_error) {}
shared_ptr<commandline::parsedParameters> params = t.getParsed();
if( params->m_addConfigFile != "" ) try {
boost::filesystem::path c( params->m_addConfigFile);
if( boost::filesystem::exists(c) && !boost::filesystem::is_directory(c) )
this->loadFile(c.native());
} catch(boost::filesystem::filesystem_error) {}
}
void ConfigFileFinder::loadFile(string filename) {
ifstream file(filename.c_str(),std::ios::in);
ostringstream reader;
reader << file.rdbuf();
string *tmp = new string(reader.str());
this->insert(this->end(),tmp);
}
void ConfigFileParser::parse(string& text) {
vector<string> lines;
config * current = &(this->basic);
vector<config> configs;
boost::split(lines,text,boost::is_any_of("\n"));
if( current->pattern != ".*" ) {
current->pattern = ".*";
current->ticketcommand = "hsadmint \\0";
current->server = "http://localhost:7777/RPC2";
current->shell = "/bin/sh";
current->askpass = false;
}
for( vector<string>::iterator i = lines.begin(); i != lines.end(); i++ ) {
string& line = *i;
// ignore coments and empty lines
boost::trim_left(line);
if( line[0] == '#' || line == "" )
continue;
// is this a section?
if( line[0] == '[' ) {
line.erase(0,1);
line.erase(line.rfind(']'));
if( current != &(this->basic) ) {
configs.insert(configs.end(),*current);
delete(current);
}
current = new config;
*current = this->basic;
current->pattern = line;
} else {
string::size_type equals = line.find('=');
string name = boost::trim_copy(line.substr(0,equals));
string value = boost::trim_copy(line.substr(equals+1));
// trim name and value
boost::trim(name);
boost::trim(value);
if( name == "ticket" )
current->ticketcommand = value;
else if( name == "server" )
current->server = value;
else if( name == "shell" )
current->shell = value;
else if( name == "askpass" && value == "true" )
current->askpass = true;
else if( name == "askpass" && value == "false" )
current->askpass = false;
}
}
if( current != &(this->basic) ) {
configs.insert(configs.end(),*current);
delete(current);
}
this->configs.insert(this->configs.begin(),configs.begin(),configs.end());
}
string ConfigFileParser::replaceStringMatches(string &userpattern, string username, string content) {
if( username == "" ) {
char* u = (char*)malloc(L_cuserid+1);;
cuserid(u);
if( u != 0 ) username = u;
}
boost::regex pattern(userpattern);
boost::cmatch results;
if( !boost::regex_match(username.c_str(),results,pattern) ) return content;
for(int j = 0; j < results.size(); j++) {
ostringstream p;
p << "^\\\\" << j << "|([^\\\\])\\\\" << j;
boost::regex pat(p.str());
string replace = "$1";
if( results[j].matched ) for( const char* i = results[j].first; i != results[j].second; i++ )
replace += *i;
content = boost::regex_replace(content,pat,replace);
}
return content;
}
string ConfigFileParser::getTicket(string &username) {
string ticketstring = "";
config cfg = this->getConfig(username);
string command = cfg.getTicketcommand(username);
Logger::log(Logger::DEBUG,"use '"+command+"' as command");
pid_t pid;
pid_t parentpid = getpid();
int cmdout[2];
if(pipe(cmdout) || (pid=fork()) == -1)
return "";
if(!pid) {
close(1);
close(cmdout[0]);
dup(cmdout[1]);
//command = cfg.shell+" -c \""+command+"\"";
// this should never return.
execlp(cfg.shell.c_str(),cfg.shell.c_str(),"-c",command.c_str(),(char*)0);
// if we have reached this something has gone wrong.
string msg = Logger::getMessageFormatString(Logger::ErrorWithTicketCommand);
boost::format fmt(msg);
fmt % cfg.shell % command % Logger::getErrnoMessage(errno);
Logger::log(Logger::FATAL,fmt.str());
exit(-1);
}
int status;
waitpid(pid,&status,0);
close(cmdout[1]);
// check if ticket has been successfully generated
if( !WIFEXITED(status) || WEXITSTATUS(status) )
exit(WEXITSTATUS(status));
char buf[257];
bzero(buf,257);
errno = 0;
int i = 0;
while( (i = read(cmdout[0],buf,256)) != 0 ) {
if( i < 0 ) {
if( errno == EAGAIN ) {
usleep(20);
continue;
} else if( errno == EINTR ) continue;
else {
string msg = Logger::getMessageFormatString(Logger::ErrorReadingTicket);
boost::format fmt(msg);
fmt % Logger::getErrnoMessage(errno);
Logger::log(Logger::FATAL,fmt.str());
exit(-1);
}
errno = 0;
}
ticketstring += buf;
if( strlen(buf) < i ) break;
bzero(buf,257);
}
return ticketstring;
}
ConfigFileParser::config &ConfigFileParser::getConfig(string &username) {
if( username == "" ) return basic;
for( vector<config>::iterator i = configs.begin(); i != configs.end(); i++ ) {
boost::regex pat(i->pattern);
if(boost::regex_match(username,pat)) return *i;
}
return basic;
}