Ejemplo n.º 1
0
KdeSudo::KdeSudo(QWidget *parent, const char *name,const QString& icon, const QString& generic, bool withIgnoreButton)
	: KPasswordDialog(KPasswordDialog::Password, false, (withIgnoreButton ? User1: false), icon, parent, name)
{
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	QString defaultComment = i18n("<b>%1</b> needs administrative privileges. Please enter your password for verification.");
	p=NULL;
	bError=false;

	m_pCookie = new KCookie;

	// Set vars
	bool newDcop = args->isSet("newdcop");
	bool realtime = args->isSet("r");
	bool priority = args->isSet("p");
	bool showCommand = (!args->isSet("d"));
	bool changeUID = true;
	bool noExec = false;
	keepPwd = (!args->isSet("n"));
	emptyPwd = args->isSet("s");
	QString runas = args->getOption("u");
	QString cmd;

	if (!args->isSet("c") && !args->count() && (!args->isSet("s")))
	{
		KMessageBox::information(NULL, i18n("No command arguments supplied!\nUsage: kdesudo [-u <runas>] <command>\nKdeSudo will now exit..."));
		noExec = true;
	}

	p = new KProcess;
	p->clearArguments();

	// Parsins args

	/* Get the comment out of cli args */
	QByteArray commentBytes = args->getOption("comment");
	QTextCodec* tCodecConv = QTextCodec::codecForLocale();
	QString comment = tCodecConv->toUnicode(commentBytes, commentBytes.size());

	if (args->isSet("f"))
	{
		// If file is writeable, do not change uid
		QString filename = QFile::decodeName(args->getOption("f"));
		QString file = filename;
		if (!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);
			}
			if (fi.isWritable())
			{
				changeUID = false;
			}
		}
	}

	if (withIgnoreButton)
	{
		setButtonText(User1, i18n("&Ignore"));
	}

	// Apologies for the C code, taken from kdelibs/kdesu/kdesu_stub.c
	// KControl and other places need to use the user's existing DCOP server
	// For that we set DCOPSERVER.  Create a file in /tmp and use iceauth to add magic cookies
	// from the existing server and set ICEAUTHORITY to point to the file
	if (!newDcop) {
		dcopServer = m_pCookie->dcopServer();
		QCString dcopAuth = m_pCookie->dcopAuth();
		QCString iceAuth = m_pCookie->iceAuth();

		FILE *fout;
		char iceauthority[200];
		char *host, *auth;
		host = qstrdup(dcopServer);
		auth = qstrdup(iceAuth);
		int tempfile;
		int oldumask = umask(077);

		strcpy(iceauthority, "/tmp/iceauth.XXXXXXXXXX");
		tempfile = mkstemp(iceauthority);
		umask(oldumask);
		if (tempfile == -1) {
			kdError() << "error in kdesudo mkstemp" << endl;
			exit(1);
		} else {
			// close(tempfile); //FIXME why does this make the connect() call later crash?
		}
		iceauthorityFile = iceauthority;
		//FIXME we should change owner of iceauthority file, but don't have permissions
		setenv("ICEAUTHORITY", iceauthorityFile, 1);
	
		fout = popen("iceauth >/dev/null 2>&1", "w");
		if (!fout) {
			kdError() << "error in kdesudo running iceauth" << endl;
			exit(1);
		}
		fprintf(fout, "add ICE \"\" %s %s\n", host, auth);
		auth = qstrdup(dcopAuth);
		//auth = xstrsep(params[P_DCOP_AUTH].value);
		fprintf(fout, "add DCOP \"\" %s %s\n", host, auth);
		unsetenv("ICEAUTHORITY");
		pclose(fout);
	}

	connect( p, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(receivedOut(KProcess*, char*, int)) );
	connect( p, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(receivedOut(KProcess*, char*, int)) );
	connect( p, SIGNAL(processExited (KProcess *)), this, SLOT(procExited(KProcess*)));

	QString xauthenv = QString(getenv("HOME")) + "/.Xauthority";
	p->setEnvironment("XAUTHORITY", xauthenv);

	// Generate the xauth cookie and put it in a tempfile
	// set the environment variables to reflect that.
	// Default cookie-timeout is 60 sec. .
	// 'man xauth' for more info on xauth cookies.
	
	KTempFile temp = KTempFile("/tmp/kdesudo-","-xauth");
	m_tmpname = temp.name();
	
	FILE *f;
	char buf[1024];
	
	QCString disp = m_pCookie->display();
	// command: xauth -q -f m_tmpname generate $DISPLAy . trusted timeout 60
	QString c = "/usr/bin/xauth -q -f " + m_tmpname + " generate " 
		+ QString::fromLocal8Bit(disp) + " . trusted timeout 60";
	blockSigChild(); // pclose uses waitpid()
	
	if (!(f = popen(c, "r"))) {
		kdWarning() << k_lineinfo << "Cannot run: " << c << "\n";
		unblockSigChild();
		return;
	}
	
	// non root users need to be able to read the xauth file.
	// the xauth file is deleted when kdesudo exits. security?
	QFile tf(m_tmpname);
	if (!runas.isEmpty() && runas != "root" && tf.exists())
		chmod(m_tmpname.ascii(),0644);
	
	QCStringList output;
	while (fgets(buf, 1024, f) > 0)
		output += buf; 
	if (pclose(f) < 0) {
		kdError() << k_lineinfo << "Could not run xauth.\n";
		unblockSigChild();
		return;
	}
	unblockSigChild();
	
	p->setEnvironment("DISPLAY", disp); 
	p->setEnvironment("XAUTHORITY", m_tmpname);

	if (emptyPwd)
		*p << "sudo" << "-k";
	else
	{
		if (changeUID)
		{
			*p << "sudo" << "-H" << "-S" << "-p" << "passprompt";

			if (!runas.isEmpty())
				*p << "-u" << runas;
		}

		if (!dcopServer.isEmpty())
			*p << "DCOPSERVER=" + dcopServer;

		if (!iceauthorityFile.isEmpty())
			*p << "ICEAUTHORITY=" + iceauthorityFile;

		if (realtime)
		{
			*p << "nice" << "-n" << "10";
			addLine(i18n("Priority:"), i18n("realtime:") + QChar(' ') + QString("50/100"));
		}
		else if (priority)
		{
			QString n = args->getOption("p");
			int intn = atoi(n);
			intn =  (intn * 40 / 100) - (20 + 0.5);
		
			QString strn;
			strn.sprintf("%d",intn);

			*p << "nice" << "-n" << strn;
			addLine(i18n("Priority:"), n + QString("/100"));
		}

		*p << "--";

		if (args->isSet("c"))
		{
			QString command = args->getOption("c");
			QStringList commandSplit = QStringList::split(" ", command);
			for (int i = 0; i < commandSplit.count(); i++)
			{
				QString toto = validArg(commandSplit[i]);
				*p << toto;
				cmd += validArg(commandSplit[i]) + QChar(' ');
			}
		}
		else if (args->count())
		{
			for (int i = 0; i < args->count(); i++)
			{
				if (i==0)
				{
					QStringList argsSplit = QStringList::split(" ", args->arg(i));
					for (int i = 0; i < argsSplit.count(); i++)
					{
						*p << validArg(argsSplit[i]);
						cmd += validArg(argsSplit[i]) + QChar(' ');
					}
				}
				else
				{
					*p << validArg(args->arg(i));
					cmd += validArg(args->arg(i)) + QChar(' ');
				}
			}
		}
		// strcmd needs to be defined
		if (showCommand && !cmd.isEmpty())
			addLine(i18n("Command:"), cmd);
	}

	if (comment.isEmpty())
	{
		if (!generic.isEmpty())
			setPrompt(defaultComment.arg(generic));
		else
			setPrompt(defaultComment.arg(cmd));
	}
	else
		setPrompt(comment);

	if (noExec)
		exit(0);
	else
		p->start( KProcess::NotifyOnExit, KProcess::All );
}
Ejemplo n.º 2
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;
}