コード例 #1
0
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;
}
コード例 #2
0
ファイル: handler.cpp プロジェクト: serghei/kde3-kdebase
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;
}
コード例 #3
0
ファイル: kdesu.cpp プロジェクト: KDE/kde-runtime
static int startApp()
{
    KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
    // Stop daemon and exit?
    if (args->isSet("s"))
    {
        KDEsuClient client;
        if (client.ping() == -1)
        {
            kError(1206) << "Daemon not running -- nothing to stop\n";
            exit(1);
        }
        if (client.stopServer() != -1)
        {
            kDebug(1206) << "Daemon stopped\n";
            exit(0);
        }
        kError(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
    QByteArray user = args->getOption("u").toLocal8Bit();
    QByteArray auth_user = user;
    struct passwd *pw = getpwnam(user);
    if (pw == 0L)
    {
        kError(1206) << "User " << user << " does not exist\n";
        exit(1);
    }
    bool other_uid = (getuid() != pw->pw_uid);
    bool change_uid = other_uid;
    if (!change_uid) {
        char *cur_user = getenv("USER");
        if (!cur_user)
            cur_user = getenv("LOGNAME");
        change_uid = (!cur_user || user != cur_user);
    }

    // If file is writeable, do not change uid
    QString file = args->getOption("f");
    if (other_uid && !file.isEmpty())
    {
        if (file.at(0) != '/')
        {
            KStandardDirs dirs;
            file = dirs.findResource("config", file);
            if (file.isEmpty())
            {
                kError(1206) << "Config file not found: " << file << "\n";
                exit(1);
            }
        }
        QFileInfo fi(file);
        if (!fi.exists())
        {
            kError(1206) << "File does not exist: " << file << "\n";
            exit(1);
        }
        change_uid = !fi.isWritable();
    }

    // Get priority/scheduler
    QString tmp = args->getOption("p");
    bool ok;
    int priority = tmp.toInt(&ok);
    if (!ok || (priority < 0) || (priority > 100))
    {
        KCmdLineArgs::usageError(i18n("Illegal priority: %1", 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").toLocal8Bit();
        // Accepting additional arguments here is somewhat weird,
        // but one can conceive use cases: have a complex command with
        // redirections and additional file names which need to be quoted
        // safely.
    }
    else
    {
        if( args->count() == 0 )
        {
            KCmdLineArgs::usageError(i18n("No command specified."));
            exit(1);
        }
    }
    for (int i = 0; i < args->count(); i++)
    {
        command += ' ';
        command += QFile::encodeName(KShell::quoteArg(args->arg(i)));
    }

    // 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())
    {
        kWarning(1206) << "Daemon not safe (not sgid), not using it.\n";
        have_daemon = false;
    }
    else if (client.ping() == -1)
    {
        if (client.startServer() == -1)
        {
            kWarning(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 withIgnoreButton = args->isSet("ignorebutton");
    int winid = -1;
    bool attach = args->isSet("attach");
    if(attach) {
        winid = args->getOption("attach").toInt(&attach, 0);  //C style parsing.  If the string begins with "0x", base 16 is used; if the string begins with "0", base 8 is used; otherwise, base 10 is used.
        if(!attach)
            kWarning(1206) << "Specified winid to attach to is not a valid number";
    } else if(args->isSet("embed")) {
        /* KDialog originally used --embed for attaching the dialog box.  However this is misleading and so we changed to --attach.
         * For consistancy, we silently map --embed to --attach */
        attach = true;
        winid = args->getOption("embed").toInt(&attach, 0);  //C style parsing.  If the string begins with "0x", base 16 is used; if the string begins with "0", base 8 is used; otherwise, base 10 is used.
        if(!attach)
            kWarning(1206) << "Specified winid to attach to is not a valid number";
    }


    QList<QByteArray> env;
    QByteArray 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.clear(); // Use default

       env << ("KDEHOME="+ QFile::encodeName(kdeHome));
    }

    KUser u;
    env << (QByteArray) ("KDESU_USER="******"rlimit(): " << ERR << "\n";
        exit(1);
    }

    // Read configuration
    KConfigGroup config(KGlobal::config(), "Passwords");
    int timeout = config.readEntry("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;
        kDebug() << "Don't need password!!\n";
    }

    // Start the dialog
    QString password;
    if (needpw)
    {
#ifdef Q_WS_X11
        KStartupInfoId id;
        id.initId( kapp->startupId());
        KStartupInfoData data;
        data.setSilent( KStartupInfoData::Yes );
        KStartupInfo::sendChange( id, data );
#endif
        KDEsuDialog dlg(user, auth_user, keep && !terminal, icon, withIgnoreButton);
        if (prompt)
            dlg.addCommentLine(i18n("Command:"), QFile::decodeName(command));
        if (defKeep)
            dlg.setKeepPassword(true);

        if ((priority != 50) || (scheduler != SuProcess::SchedNormal))
        {
            QString prio;
            if (scheduler == SuProcess::SchedRealtime)
                prio += i18n("realtime: ");
            prio += QString("%1/100").arg(priority);
            if (prompt)
                dlg.addCommentLine(i18n("Priority:"), prio);
        }

	//Attach dialog
#ifdef Q_WS_X11
	if(attach)
            KWindowSystem::setMainWindow(&dlg, (WId)winid);
#endif
        int ret = dlg.exec();
        if (ret == KDEsuDialog::Rejected)
        {
#ifdef Q_WS_X11
            KStartupInfo::sendFinish( id );
#endif
            exit(1);
        }
        if (ret == KDEsuDialog::AsUser)
            change_uid = false;
        password = dlg.password();
        keep = dlg.keepPassword();
#ifdef Q_WS_X11
        data.setSilent( KStartupInfoData::No );
        KStartupInfo::sendChange( id, data );
#endif
    }

    // 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.toLocal8Bit(), 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);
        proc.setEnvironment(env);
        proc.setPriority(priority);
        proc.setScheduler(scheduler);
        proc.setCommand(command);
        int result = proc.exec(password.toLocal8Bit());
        return result;
    }
    return -1;
}