int xio_errhandler(Display *) { kdError(1205) << "Fatal IO error, exiting...\n"; kdesud_cleanup(); exit(1); return 1; //silence compilers }
int ConnectionHandler::doCommand(QCString buf) { if((uid_t)peerUid() != getuid()) { kdWarning(1205) << "Peer uid not equal to me\n"; kdWarning(1205) << "Peer: " << peerUid() << " Me: " << getuid() << endl; return -1; } QCString key, command, pass, name, user, value, env_check; Data_entry data; Lexer *l = new Lexer(buf); int tok = l->lex(); switch(tok) { case Lexer::Tok_pass: // "PASS password:string timeout:int\n" tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; m_Pass.fill('x'); 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; if(m_Pass.isNull()) m_Pass = ""; kdDebug(1205) << "Password set!\n"; respond(Res_OK); break; case Lexer::Tok_host: // "HOST host:string\n" tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; m_Host = l->lval(); if(l->lex() != '\n') goto parse_error; kdDebug(1205) << "Host set to " << m_Host << endl; respond(Res_OK); break; case Lexer::Tok_prio: // "PRIO priority:int\n" tok = l->lex(); if(tok != Lexer::Tok_num) goto parse_error; m_Priority = l->lval().toInt(); if(l->lex() != '\n') goto parse_error; kdDebug(1205) << "priority set to " << m_Priority << endl; respond(Res_OK); break; case Lexer::Tok_sched: // "SCHD scheduler:int\n" tok = l->lex(); if(tok != Lexer::Tok_num) goto parse_error; m_Scheduler = l->lval().toInt(); if(l->lex() != '\n') goto parse_error; kdDebug(1205) << "Scheduler set to " << m_Scheduler << endl; respond(Res_OK); break; case Lexer::Tok_exec: // "EXEC command:string user:string [options:string (env:string)*]\n" { QCString options; KStringList env; tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; command = l->lval(); tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; user = l->lval(); tok = l->lex(); if(tok != '\n') { if(tok != Lexer::Tok_str) goto parse_error; options = l->lval(); tok = l->lex(); while(tok != '\n') { if(tok != Lexer::Tok_str) goto parse_error; QCString env_str = l->lval(); env.append(env_str); if(strncmp(env_str, "DESKTOP_STARTUP_ID=", strlen("DESKTOP_STARTUP_ID=")) != 0) env_check += "*" + env_str; tok = l->lex(); } } QCString auth_user; if((m_Scheduler != SuProcess::SchedNormal) || (m_Priority > 50)) auth_user = "******"; else auth_user = user; key = makeKey(2, m_Host, auth_user, command); // We only use the command if the environment is the same. if(repo->find(key) == env_check) { key = makeKey(0, m_Host, auth_user, command); pass = repo->find(key); } if(pass.isNull()) // isNull() means no password, isEmpty() can mean empty password { if(m_Pass.isNull()) { respond(Res_NO); break; } data.value = env_check; data.timeout = m_Timeout; key = makeKey(2, m_Host, auth_user, command); repo->add(key, data); data.value = m_Pass; data.timeout = m_Timeout; key = makeKey(0, m_Host, auth_user, command); repo->add(key, data); pass = m_Pass; } // Execute the command asynchronously kdDebug(1205) << "Executing command: " << command << endl; pid_t pid = fork(); if(pid < 0) { kdDebug(1205) << "fork(): " << strerror(errno) << endl; respond(Res_NO); break; } else if(pid > 0) { m_pid = pid; 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(user); if(options.contains('x')) proc.setXOnly(true); if(options.contains('f')) proc.setDCOPForwarding(true); proc.setPriority(m_Priority); proc.setScheduler(m_Scheduler); proc.setEnvironment(env); ret = proc.exec(pass.data()); } else { SshProcess proc; proc.setCommand(command); proc.setUser(user); proc.setHost(m_Host); ret = proc.exec(pass.data()); } kdDebug(1205) << "Command completed: " << command << endl; _exit(ret); } case Lexer::Tok_delCmd: // "DEL command:string user:string\n" tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; command = l->lval(); tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; user = l->lval(); if(l->lex() != '\n') goto parse_error; key = makeKey(0, m_Host, user, command); if(repo->remove(key) < 0) { kdDebug(1205) << "Unknown command: " << command << endl; respond(Res_NO); } else { kdDebug(1205) << "Deleted command: " << command << ", user = "******"DELV name:string \n" { tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; name = l->lval(); tok = l->lex(); if(tok != '\n') goto parse_error; key = makeKey(1, name); if(repo->remove(key) < 0) { kdDebug(1205) << "Unknown name: " << name << endl; respond(Res_NO); } else { kdDebug(1205) << "Deleted name: " << name << endl; respond(Res_OK); } break; } case Lexer::Tok_delGroup: // "DELG group:string\n" tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; name = l->lval(); if(repo->removeGroup(name) < 0) { kdDebug(1205) << "No keys found under group: " << name << endl; respond(Res_NO); } else { kdDebug(1205) << "Removed all keys under group: " << name << endl; respond(Res_OK); } break; case Lexer::Tok_delSpecialKey: // "DELS special_key:string\n" tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; name = l->lval(); if(repo->removeSpecialKey(name) < 0) respond(Res_NO); else respond(Res_OK); break; case Lexer::Tok_set: // "SET name:string value:string group:string timeout:int\n" tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; name = l->lval(); tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; data.value = l->lval(); tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; data.group = l->lval(); tok = l->lex(); if(tok != Lexer::Tok_num) goto parse_error; data.timeout = l->lval().toInt(); if(l->lex() != '\n') goto parse_error; key = makeKey(1, name); repo->add(key, data); kdDebug(1205) << "Stored key: " << key << endl; respond(Res_OK); break; case Lexer::Tok_get: // "GET name:string\n" tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; name = l->lval(); if(l->lex() != '\n') goto parse_error; key = makeKey(1, name); kdDebug(1205) << "Request for key: " << key << endl; value = repo->find(key); if(!value.isEmpty()) respond(Res_OK, value); else respond(Res_NO); break; case Lexer::Tok_getKeys: // "GETK groupname:string\n" tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; name = l->lval(); if(l->lex() != '\n') goto parse_error; kdDebug(1205) << "Request for group key: " << name << endl; value = repo->findKeys(name); if(!value.isEmpty()) respond(Res_OK, value); else respond(Res_NO); break; case Lexer::Tok_chkGroup: // "CHKG groupname:string\n" tok = l->lex(); if(tok != Lexer::Tok_str) goto parse_error; name = l->lval(); if(l->lex() != '\n') goto parse_error; kdDebug(1205) << "Checking for group key: " << name << endl; if(repo->hasGroup(name) < 0) respond(Res_NO); else respond(Res_OK); break; case Lexer::Tok_ping: // "PING\n" tok = l->lex(); if(tok != '\n') goto parse_error; respond(Res_OK); break; case Lexer::Tok_exit: // "EXIT\n" tok = l->lex(); if(tok != '\n') goto parse_error; m_needExitCode = true; if(m_hasExitCode) sendExitCode(); break; case Lexer::Tok_stop: // "STOP\n" tok = l->lex(); if(tok != '\n') goto parse_error; kdDebug(1205) << "Stopping by command" << endl; respond(Res_OK); kdesud_cleanup(); exit(0); default: kdWarning(1205) << "Unknown command: " << l->lval() << endl; respond(Res_NO); goto parse_error; } delete l; return 0; parse_error: kdWarning(1205) << "Parse error" << endl; delete l; return -1; }
int main(int argc, char *argv[]) { KAboutData aboutData("kdesud", I18N_NOOP("KDE su daemon"), Version, I18N_NOOP("Daemon used by kdesu"), KAboutData::License_Artistic, "Copyright (c) 1999,2000 Geert Jansen"); aboutData.addAuthor("Geert Jansen", I18N_NOOP("Author"), "*****@*****.**", "http://www.stack.nl/~geertj/"); KCmdLineArgs::init(argc, argv, &aboutData); KInstance instance(&aboutData); // Set core dump size to 0 struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &rlim) < 0) { kdError(1205) << "setrlimit(): " << ERR << "\n"; exit(1); } // Create the Unix socket. int sockfd = create_socket(); if (sockfd < 0) exit(1); if (listen(sockfd, 1) < 0) { kdError(1205) << "listen(): " << ERR << "\n"; kdesud_cleanup(); exit(1); } int maxfd = sockfd; // Ok, we're accepting connections. Fork to the background. pid_t pid = fork(); if (pid == -1) { kdError(1205) << "fork():" << ERR << "\n"; kdesud_cleanup(); exit(1); } if (pid) exit(0); // Make sure we exit when the display gets closed. int x11Fd = initXconnection(); maxfd = QMAX(maxfd, x11Fd); repo = new Repository; QPtrVector<ConnectionHandler> handler; handler.setAutoDelete(true); pipe(pipeOfDeath); maxfd = QMAX(maxfd, pipeOfDeath[0]); // Signal handlers struct sigaction sa; sa.sa_handler = signal_exit; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; sigaction(SIGHUP, &sa, 0L); sigaction(SIGINT, &sa, 0L); sigaction(SIGTERM, &sa, 0L); sigaction(SIGQUIT, &sa, 0L); sa.sa_handler = sigchld_handler; sa.sa_flags = SA_NOCLDSTOP; sigaction(SIGCHLD, &sa, 0L); sa.sa_handler = SIG_IGN; sigaction(SIGPIPE, &sa, 0L); // Main execution loop ksocklen_t addrlen; struct sockaddr_un clientname; fd_set tmp_fds, active_fds; FD_ZERO(&active_fds); FD_SET(sockfd, &active_fds); FD_SET(pipeOfDeath[0], &active_fds); if (x11Fd != -1) FD_SET(x11Fd, &active_fds); while (1) { tmp_fds = active_fds; if(x11Display) XFlush(x11Display); if (select(maxfd+1, &tmp_fds, 0L, 0L, 0L) < 0) { if (errno == EINTR) continue; kdError(1205) << "select(): " << ERR << "\n"; exit(1); } repo->expire(); for (int i=0; i<=maxfd; i++) { if (!FD_ISSET(i, &tmp_fds)) continue; if (i == pipeOfDeath[0]) { char buf[101]; read(pipeOfDeath[0], buf, 100); pid_t result; do { int status; result = waitpid((pid_t)-1, &status, WNOHANG); if (result > 0) { for(int j=handler.size(); j--;) { if (handler[j] && (handler[j]->m_pid == result)) { handler[j]->m_exitCode = WEXITSTATUS(status); handler[j]->m_hasExitCode = true; handler[j]->sendExitCode(); handler[j]->m_pid = 0; break; } } } } while(result > 0); } if (i == x11Fd) { // Discard X events XEvent event_return; if (x11Display) while(XPending(x11Display)) XNextEvent(x11Display, &event_return); continue; } if (i == sockfd) { // Accept new connection int fd; addrlen = 64; fd = accept(sockfd, (struct sockaddr *) &clientname, &addrlen); if (fd < 0) { kdError(1205) << "accept():" << ERR << "\n"; continue; } if (fd+1 > (int) handler.size()) handler.resize(fd+1); handler.insert(fd, new ConnectionHandler(fd)); maxfd = QMAX(maxfd, fd); FD_SET(fd, &active_fds); continue; } // handle alreay established connection if (handler[i] && handler[i]->handle() < 0) { handler.remove(i); FD_CLR(i, &active_fds); } } } kdWarning(1205) << "???\n"; }
void signal_exit(int sig) { kdDebug(1205) << "Exiting on signal " << sig << "\n"; kdesud_cleanup(); exit(1); }