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; }
static int startApp() { KCmdLineArgs *args = KCmdLineArgs::parsedArgs(); // Stop daemon and exit? if (args->isSet("s")) { KDEsuClient client; if (client.ping() == -1) { kdError(1206) << "Daemon not running -- nothing to stop\n"; exit(1); } if (client.stopServer() != -1) { kdDebug(1206) << "Daemon stopped\n"; exit(0); } kdError(1206) << "Could not stop daemon\n"; exit(1); } QString icon; if ( args->isSet("i")) icon = args->getOption("i"); bool prompt = true; if ( args->isSet("d")) prompt = false; // Get target uid QCString user = args->getOption("u"); QCString auth_user = user; struct passwd *pw = getpwnam(user); if (pw == 0L) { kdError(1206) << "User " << user << " does not exist\n"; exit(1); } bool change_uid = (getuid() != pw->pw_uid); // If file is writeable, do not change uid QString file = QFile::decodeName(args->getOption("f")); if (change_uid && !file.isEmpty()) { if (file.at(0) != '/') { KStandardDirs dirs; dirs.addKDEDefaults(); file = dirs.findResource("config", file); if (file.isEmpty()) { kdError(1206) << "Config file not found: " << file << "\n"; exit(1); } } QFileInfo fi(file); if (!fi.exists()) { kdError(1206) << "File does not exist: " << file << "\n"; exit(1); } change_uid = !fi.isWritable(); } // Get priority/scheduler QCString tmp = args->getOption("p"); bool ok; int priority = tmp.toInt(&ok); if (!ok || (priority < 0) || (priority > 100)) { KCmdLineArgs::usage(i18n("Illegal priority: %1").arg(tmp)); exit(1); } int scheduler = SuProcess::SchedNormal; if (args->isSet("r")) scheduler = SuProcess::SchedRealtime; if ((priority > 50) || (scheduler != SuProcess::SchedNormal)) { change_uid = true; auth_user = "******"; } // Get command if (args->isSet("c")) { command = args->getOption("c"); for (int i=0; i<args->count(); i++) { QString arg = QFile::decodeName(args->arg(i)); KRun::shellQuote(arg); command += " "; command += QFile::encodeName(arg); } } else { if( args->count() == 0 ) { KCmdLineArgs::usage(i18n("No command specified.")); exit(1); } command = args->arg(0); for (int i=1; i<args->count(); i++) { QString arg = QFile::decodeName(args->arg(i)); KRun::shellQuote(arg); command += " "; command += QFile::encodeName(arg); } } // Don't change uid if we're don't need to. if (!change_uid) { int result = system(command); result = WEXITSTATUS(result); return result; } // Check for daemon and start if necessary bool just_started = false; bool have_daemon = true; KDEsuClient client; if (!client.isServerSGID()) { kdWarning(1206) << "Daemon not safe (not sgid), not using it.\n"; have_daemon = false; } else if (client.ping() == -1) { if (client.startServer() == -1) { kdWarning(1206) << "Could not start daemon, reduced functionality.\n"; have_daemon = false; } just_started = true; } // Try to exec the command with kdesud. bool keep = !args->isSet("n") && have_daemon; bool terminal = args->isSet("t"); bool new_dcop = args->isSet("newdcop"); bool withIgnoreButton = args->isSet("ignorebutton"); QCStringList env; QCString options; env << ( "DESKTOP_STARTUP_ID=" + kapp->startupId()); if (pw->pw_uid) { // Only propagate KDEHOME for non-root users, // root uses KDEROOTHOME // Translate the KDEHOME of this user to the new user. QString kdeHome = KGlobal::dirs()->relativeLocation("home", KGlobal::dirs()->localkdedir()); if (kdeHome[0] != '/') kdeHome.prepend("~/"); else kdeHome=QString::null; // Use default env << ("KDEHOME="+ QFile::encodeName(kdeHome)); } KUser u; env << (QCString) ("KDESU_USER="******"KDESYCOCA="+QFile::encodeName(locateLocal("cache", "ksycoca")); env << ksycoca; options += "xf"; // X-only, dcop forwarding enabled. } if (keep && !terminal && !just_started) { client.setPriority(priority); client.setScheduler(scheduler); int result = client.exec(command, user, options, env); if (result == 0) { result = client.exitCode(); return result; } } // Set core dump size to 0 because we will have // root's password in memory. struct rlimit rlim; rlim.rlim_cur = rlim.rlim_max = 0; if (setrlimit(RLIMIT_CORE, &rlim)) { kdError(1206) << "rlimit(): " << ERR << "\n"; exit(1); } // Read configuration KConfig *config = KGlobal::config(); config->setGroup("Passwords"); int timeout = config->readNumEntry("Timeout", defTimeout); // Check if we need a password SuProcess proc; proc.setUser(auth_user); int needpw = proc.checkNeedPassword(); if (needpw < 0) { QString err = i18n("Su returned with an error.\n"); KMessageBox::error(0L, err); exit(1); } if (needpw == 0) { keep = 0; kdDebug() << "Don't need password!!\n"; } // Start the dialog QCString password; if (needpw) { KStartupInfoId id; id.initId( kapp->startupId()); KStartupInfoData data; data.setSilent( KStartupInfoData::Yes ); KStartupInfo::sendChange( id, data ); KDEsuDialog dlg(user, auth_user, keep && !terminal,icon, withIgnoreButton); if (prompt) dlg.addLine(i18n("Command:"), command); if ((priority != 50) || (scheduler != SuProcess::SchedNormal)) { QString prio; if (scheduler == SuProcess::SchedRealtime) prio += i18n("realtime: "); prio += QString("%1/100").arg(priority); if (prompt) dlg.addLine(i18n("Priority:"), prio); } int ret = dlg.exec(); if (ret == KDEsuDialog::Rejected) { KStartupInfo::sendFinish( id ); exit(0); } if (ret == KDEsuDialog::AsUser) change_uid = false; password = dlg.password(); keep = dlg.keep(); data.setSilent( KStartupInfoData::No ); KStartupInfo::sendChange( id, data ); } // Some events may need to be handled (like a button animation) kapp->processEvents(); // Run command if (!change_uid) { int result = system(command); result = WEXITSTATUS(result); return result; } else if (keep && have_daemon) { client.setPass(password, timeout); client.setPriority(priority); client.setScheduler(scheduler); int result = client.exec(command, user, options, env); if (result == 0) { result = client.exitCode(); return result; } } else { SuProcess proc; proc.setTerminal(terminal); proc.setErase(true); proc.setUser(user); if (!new_dcop) { proc.setXOnly(true); proc.setDCOPForwarding(true); } proc.setEnvironment(env); proc.setPriority(priority); proc.setScheduler(scheduler); proc.setCommand(command); int result = proc.exec(password); return result; } return -1; }