2 * This file is part of the KDE project, module kdesu.
3 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
5 * handler.cpp: A connection handler for kdesud.
17 #include <sys/types.h>
18 #include <sys/socket.h>
22 #include <kdesu/ssh.h>
28 using namespace KDESu
;
32 extern Repository
*repo
;
33 void kdesud_cleanup();
35 ConnectionHandler::ConnectionHandler(int fd
)
36 : SocketSecurity(fd
), m_exitCode(0), m_hasExitCode(false), m_needExitCode(false), m_pid(0)
40 m_Scheduler
= SuProcess::SchedNormal
;
43 ConnectionHandler::~ConnectionHandler()
51 * Handle a connection: make sure we don't block
54 int ConnectionHandler::handle()
58 // Add max 100 bytes to connection buffer
61 nbytes
= recv(m_Fd
, tmpbuf
, 99, 0);
69 } else if (nbytes
== 0)
74 tmpbuf
[nbytes
] = '\000';
76 if (m_Buf
.length()+nbytes
> 1024)
78 kWarning(1205) << "line too long";
83 memset(tmpbuf
, 'x', nbytes
);
85 // Do we have a complete command yet?
88 while ((n
= m_Buf
.indexOf('\n')) != -1)
90 newbuf
= m_Buf
.left(n
+1);
93 ret
= doCommand(newbuf
);
101 QByteArray
ConnectionHandler::makeKey(int _namespace
, const QByteArray
&s1
,
102 const QByteArray
&s2
, const QByteArray
&s3
) const
105 res
.setNum(_namespace
);
107 res
+= s1
+ '*' + s2
+ '*' + s3
;
111 void ConnectionHandler::sendExitCode()
116 buf
.setNum(m_exitCode
);
120 send(m_Fd
, buf
.data(), buf
.length(), 0);
123 void ConnectionHandler::respond(int ok
, const QByteArray
&s
)
145 send(m_Fd
, buf
.data(), buf
.length(), 0);
149 * Parse and do one command. On a parse error, return -1. This will
150 * close the socket in the main accept loop.
153 int ConnectionHandler::doCommand(QByteArray buf
)
155 if ((uid_t
) peerUid() != getuid())
157 kWarning(1205) << "Peer uid not equal to me\n";
158 kWarning(1205) << "Peer: " << peerUid() << " Me: " << getuid() ;
162 QByteArray key
, command
, pass
, name
, user
, value
, env_check
;
165 Lexer
*l
= new Lexer(buf
);
169 case Lexer::Tok_pass
: // "PASS password:string timeout:int\n"
171 if (tok
!= Lexer::Tok_str
)
176 if (tok
!= Lexer::Tok_num
)
178 m_Timeout
= l
->lval().toInt();
179 if (l
->lex() != '\n')
183 kDebug(1205) << "Password set!\n";
187 case Lexer::Tok_host
: // "HOST host:string\n"
189 if (tok
!= Lexer::Tok_str
)
192 if (l
->lex() != '\n')
194 kDebug(1205) << "Host set to " << m_Host
;
198 case Lexer::Tok_prio
: // "PRIO priority:int\n"
200 if (tok
!= Lexer::Tok_num
)
202 m_Priority
= l
->lval().toInt();
203 if (l
->lex() != '\n')
205 kDebug(1205) << "priority set to " << m_Priority
;
209 case Lexer::Tok_sched
: // "SCHD scheduler:int\n"
211 if (tok
!= Lexer::Tok_num
)
213 m_Scheduler
= l
->lval().toInt();
214 if (l
->lex() != '\n')
216 kDebug(1205) << "Scheduler set to " << m_Scheduler
;
220 case Lexer::Tok_exec
: // "EXEC command:string user:string [options:string (env:string)*]\n"
223 QList
<QByteArray
> env
;
225 if (tok
!= Lexer::Tok_str
)
229 if (tok
!= Lexer::Tok_str
)
235 if (tok
!= Lexer::Tok_str
)
241 if (tok
!= Lexer::Tok_str
)
243 QByteArray env_str
= l
->lval();
245 if (strncmp(env_str
, "DESKTOP_STARTUP_ID=", strlen("DESKTOP_STARTUP_ID=")) != 0)
246 env_check
+= '*'+env_str
;
251 QByteArray auth_user
;
252 if ((m_Scheduler
!= SuProcess::SchedNormal
) || (m_Priority
> 50))
256 key
= makeKey(2, m_Host
, auth_user
, command
);
257 // We only use the command if the environment is the same.
258 if (repo
->find(key
) == env_check
)
260 key
= makeKey(0, m_Host
, auth_user
, command
);
261 pass
= repo
->find(key
);
263 if (pass
.isNull()) // isNull() means no password, isEmpty() can mean empty password
270 data
.value
= env_check
;
271 data
.timeout
= m_Timeout
;
272 key
= makeKey(2, m_Host
, auth_user
, command
);
273 repo
->add(key
, data
);
275 data
.timeout
= m_Timeout
;
276 key
= makeKey(0, m_Host
, auth_user
, command
);
277 repo
->add(key
, data
);
281 // Execute the command asynchronously
282 kDebug(1205) << "Executing command: " << command
;
286 kDebug(1205) << "fork(): " << strerror(errno
);
296 // Ignore SIGCHLD because "class SuProcess" needs waitpid()
297 signal(SIGCHLD
, SIG_DFL
);
300 if (m_Host
.isEmpty())
303 proc
.setCommand(command
);
305 if (options
.contains('x'))
307 proc
.setPriority(m_Priority
);
308 proc
.setScheduler(m_Scheduler
);
309 proc
.setEnvironment(env
);
310 ret
= proc
.exec(pass
.data());
314 proc
.setCommand(command
);
316 proc
.setHost(m_Host
);
317 ret
= proc
.exec(pass
.data());
320 kDebug(1205) << "Command completed: " << command
;
324 case Lexer::Tok_delCmd
: // "DEL command:string user:string\n"
326 if (tok
!= Lexer::Tok_str
)
330 if (tok
!= Lexer::Tok_str
)
333 if (l
->lex() != '\n')
335 key
= makeKey(0, m_Host
, user
, command
);
336 if (repo
->remove(key
) < 0) {
337 kDebug(1205) << "Unknown command: " << command
;
341 kDebug(1205) << "Deleted command: " << command
<< ", user = "
347 case Lexer::Tok_delVar
: // "DELV name:string \n"
350 if (tok
!= Lexer::Tok_str
)
356 key
= makeKey(1, name
);
357 if (repo
->remove(key
) < 0)
359 kDebug(1205) << "Unknown name: " << name
;
363 kDebug(1205) << "Deleted name: " << name
;
369 case Lexer::Tok_delGroup
: // "DELG group:string\n"
371 if (tok
!= Lexer::Tok_str
)
374 if (repo
->removeGroup(name
) < 0)
376 kDebug(1205) << "No keys found under group: " << name
;
381 kDebug(1205) << "Removed all keys under group: " << name
;
386 case Lexer::Tok_delSpecialKey
: // "DELS special_key:string\n"
388 if (tok
!= Lexer::Tok_str
)
391 if (repo
->removeSpecialKey(name
) < 0)
397 case Lexer::Tok_set
: // "SET name:string value:string group:string timeout:int\n"
399 if (tok
!= Lexer::Tok_str
)
403 if (tok
!= Lexer::Tok_str
)
405 data
.value
= l
->lval();
407 if (tok
!= Lexer::Tok_str
)
409 data
.group
= l
->lval();
411 if (tok
!= Lexer::Tok_num
)
413 data
.timeout
= l
->lval().toInt();
414 if (l
->lex() != '\n')
416 key
= makeKey(1, name
);
417 repo
->add(key
, data
);
418 kDebug(1205) << "Stored key: " << key
;
422 case Lexer::Tok_get
: // "GET name:string\n"
424 if (tok
!= Lexer::Tok_str
)
427 if (l
->lex() != '\n')
429 key
= makeKey(1, name
);
430 kDebug(1205) << "Request for key: " << key
;
431 value
= repo
->find(key
);
432 if (!value
.isEmpty())
433 respond(Res_OK
, value
);
438 case Lexer::Tok_getKeys
: // "GETK groupname:string\n"
440 if (tok
!= Lexer::Tok_str
)
443 if (l
->lex() != '\n')
445 kDebug(1205) << "Request for group key: " << name
;
446 value
= repo
->findKeys(name
);
447 if (!value
.isEmpty())
448 respond(Res_OK
, value
);
453 case Lexer::Tok_chkGroup
: // "CHKG groupname:string\n"
455 if (tok
!= Lexer::Tok_str
)
458 if (l
->lex() != '\n')
460 kDebug(1205) << "Checking for group key: " << name
;
461 if ( repo
->hasGroup( name
) < 0 )
467 case Lexer::Tok_ping
: // "PING\n"
474 case Lexer::Tok_exit
: // "EXIT\n"
478 m_needExitCode
= true;
483 case Lexer::Tok_stop
: // "STOP\n"
487 kDebug(1205) << "Stopping by command";
493 kWarning(1205) << "Unknown command: " << l
->lval() ;
502 kWarning(1205) << "Parse error" ;