Source Code (Use browser search to find items of interest.)
Class Index
kdesu'ConnectionHandler (./kdebase/kdesu/kdesud/handler.h:23)
class ConnectionHandler: public SocketSecurity
{
public:
ConnectionHandler(int fd);
~ConnectionHandler();
/**
* Call this when there is data to read from the socket.
*/
int handle();
private:
int doCommand();
void respond(int ok, QCString s=0);
QCString makeKey(int namspace, QCString host, QCString user,
QCString command);
enum Results { Res_OK, Res_NO };
int m_Fd, m_Timeout;
int m_Priority, m_Scheduler;
QCString m_Buf, m_Pass;
QCString m_User, m_Host;
};
kdesu'ConnectionHandler::ConnectionHandler() (./kdebase/kdesu/kdesud/handler.cpp:40)
ConnectionHandler::ConnectionHandler(int fd)
: SocketSecurity(fd)
{
m_Fd = fd;
m_Priority = 50;
m_Scheduler = SuProcess::SchedNormal;
}
kdesu'ConnectionHandler::~ConnectionHandler() (./kdebase/kdesu/kdesud/handler.cpp:48)
ConnectionHandler::~ConnectionHandler()
{
m_Buf.fill('x');
m_Pass.fill('x');
close(m_Fd);
}
kdesu'ConnectionHandler::respond() (./kdebase/kdesu/kdesud/handler.cpp:55)
void ConnectionHandler::respond(int ok, QCString s)
{
QCString buf;
switch (ok) {
case Res_OK:
buf = "OK";
break;
case Res_NO:
buf = "NO";
break;
default:
assert(1);
}
if (!s.isEmpty()) {
buf += ' ';
buf += s;
}
buf += '\n';
send(m_Fd, buf.data(), buf.length(), 0);
}
kdesu'ConnectionHandler::makeKey() (./kdebase/kdesu/kdesud/handler.cpp:79)
QCString ConnectionHandler::makeKey(int namspace, QCString host,
QCString user, QCString command)
{
QCString res;
res.setNum(namspace);
res += "*";
res += host + "*" + user + "*" + command;
return res;
}
/**
* Parse and do one command. On a parse error, return -1. This will
* close the socket in the main accept loop.
*/
kdesu'ConnectionHandler::doCommand() (./kdebase/kdesu/kdesud/handler.cpp:94)
int ConnectionHandler::doCommand()
{
if ((uid_t) peerUid() != getuid()) {
kDebugError("Peer uid not equal to me");
kDebugError("Peer: %d, Me: %d", peerUid(), (int) getuid());
return -1;
}
int n = m_Buf.find('\n');
assert(n != -1);
QCString newbuf = m_Buf.mid(0, n+1);
for (int i=0; i<=n; i++)
m_Buf[n] = 'x';
m_Buf.remove(0, n+1);
/* I'd like to use auto_ptr here, but egcs 1.1.2 has it
* commented out.. */
Lexer *l = new Lexer(newbuf);
int tok = l->lex();
QCString key, command, pass;
Data_entry data;
const Data_entry *pdata;
switch (tok) {
case Lexer::Tok_pass:
tok = l->lex();
if (tok != Lexer::Tok_str)
goto parse_error;
m_Pass = l->lval();
tok = l->lex();
if (tok != Lexer::Tok_num)
goto parse_error;
m_Timeout = l->lval().toInt();
if (l->lex() != '\n')
goto parse_error;
respond(Res_OK);
kDebugInfo("kdesud: Password set!");
break;
case Lexer::Tok_user:
tok = l->lex();
if (tok != Lexer::Tok_str)
goto parse_error;
m_User = l->lval();
if (l->lex() != '\n')
goto parse_error;
respond(Res_OK);
kDebugInfo("kdesud: User set to %s", m_User.data());
break;
case Lexer::Tok_host:
tok = l->lex();
if (tok != Lexer::Tok_str)
goto parse_error;
m_Host = l->lval();
if (l->lex() != '\n')
goto parse_error;
respond(Res_OK);
kDebugInfo("kdesud: Host set to %s", m_Host.data());
break;
case Lexer::Tok_prio:
tok = l->lex();
if (tok != Lexer::Tok_num)
goto parse_error;
m_Priority = l->lval().toInt();
if (l->lex() != '\n')
goto parse_error;
respond(Res_OK);
kDebugInfo("kdesud: priority set to %d", m_Priority);
break;
case Lexer::Tok_sched:
tok = l->lex();
if (tok != Lexer::Tok_num)
goto parse_error;
m_Scheduler = l->lval().toInt();
if (l->lex() != '\n')
goto parse_error;
respond(Res_OK);
kDebugInfo("kdesud: Scheduler set to %d", m_Scheduler);
break;
case Lexer::Tok_exec:
{
tok = l->lex();
if (tok != Lexer::Tok_str)
goto parse_error;
command = l->lval();
if (l->lex() != '\n')
goto parse_error;
if (m_User.isEmpty())
goto parse_error;
QCString auth_user;
if ((m_Scheduler != SuProcess::SchedNormal) || (m_Priority > 50))
auth_user = "root";
else
auth_user = m_User;
key = makeKey(0, m_Host, auth_user, command);
pdata = repo->find(key);
if (!pdata) {
if (m_Pass.isNull()) {
respond(Res_NO);
break;
}
data.value = m_Pass;
data.timeout = m_Timeout;
repo->add(key, data);
pass = m_Pass;
} else
pass = pdata->value;
// Execute the command asynchronously
kDebugInfo("kdesud: Executing command: %s", command.data());
pid_t pid = fork();
if (pid < 0) {
kDebugPError("fork()");
respond(Res_NO);
break;
} else if (pid > 0) {
respond(Res_OK);
break;
}
// Ignore SIGCHLD because "class SuProcess" needs waitpid()
signal(SIGCHLD, SIG_DFL);
int ret;
if (m_Host.isEmpty()) {
SuProcess proc;
proc.setCommand(command);
proc.setUser(m_User);
proc.setPriority(m_Priority);
proc.setScheduler(m_Scheduler);
ret = proc.exec(pass.data());
} else {
SshProcess proc;
proc.setCommand(command);
proc.setUser(m_User);
proc.setHost(m_Host);
ret = proc.exec(pass.data());
}
kDebugInfo("kdesud: Command completed");
_exit(ret);
}
case Lexer::Tok_del:
tok = l->lex();
if (tok != Lexer::Tok_str)
goto parse_error;
command = l->lval();
if (l->lex() != '\n')
goto parse_error;
if (m_User.isEmpty())
goto parse_error;
key = makeKey(0, m_Host, m_User, command);
pdata = repo->find(key);
if (!pdata) {
respond(Res_NO);
break;
}
repo->remove(key);
respond(Res_OK);
kDebugInfo("kdesud: Deleted key: %s", (const char *) key);
break;
case Lexer::Tok_set:
tok = l->lex();
if (tok != Lexer::Tok_str)
goto parse_error;
key = QCString("1*") + l->lval();
tok = l->lex();
if (tok != Lexer::Tok_str)
goto parse_error;
data.value = l->lval();
if (l->lex() != '\n')
goto parse_error;
data.timeout = 86400;
repo->add(key, data);
kDebugInfo("kdesud: stored key: %s", key.data());
respond(Res_OK);
break;
case Lexer::Tok_get:
tok = l->lex();
if (tok != Lexer::Tok_str)
goto parse_error;
key = QCString("1*") + l->lval();
if (l->lex() != '\n')
goto parse_error;
kDebugInfo("kdesud: request for key: %s", key.data());
pdata = repo->find(key);
if (pdata)
respond(Res_OK, pdata->value);
else
respond(Res_NO);
break;
case Lexer::Tok_ping:
tok = l->lex();
if (tok != '\n')
goto parse_error;
respond(Res_OK);
kDebugInfo("kdesud: PING");
break;
case Lexer::Tok_stop:
tok = l->lex();
if (tok != '\n')
goto parse_error;
respond(Res_OK);
kDebugInfo("kdesud: Stopping by command");
kdesud_cleanup();
exit(0);
default:
kDebugInfo("kdesud: Uknown command: %s", l->lval().data());
goto parse_error;
}
delete l;
return 0;
parse_error:
kDebugInfo("kdesud: Parse error");
delete l;
return -1;
}
/**
* Handle a connection: make sure we don't block
*/
kdesu'ConnectionHandler::handle() (./kdebase/kdesu/kdesud/handler.cpp:337)
int ConnectionHandler::handle()
{
int ret, nbytes;
/* Add max # bytes to connection buffer */
char tmpbuf[100];
nbytes = recv(m_Fd, tmpbuf, 99, 0);
if (nbytes < 0) {
if (errno == EINTR)
return 0;
// read error
return -1;
} else if (nbytes == 0) {
// eof
kDebugInfo("kdesud: eof on fd %d", m_Fd);
return -1;
}
tmpbuf[nbytes] = '\000';
if (m_Buf.length()+nbytes > 500) {
kDebugWarning("kdesud: line too long");
return -1;
}
m_Buf.append(tmpbuf);
memset(tmpbuf, 'x', nbytes);
/* Do we have a complete command yet? */
while (m_Buf.find('\n') != -1) {
ret = doCommand();
if (ret < 0)
return ret;
}
return 0;
}