258 lines
7.3 KiB
C++
258 lines
7.3 KiB
C++
|
/***************************************************************************
|
||
|
* 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;
|
||
|
}
|
||
|
|