File indexing completed on 2024-04-21 03:53:58

0001 /*
0002     This file is part of the KDE project, module kdesu.
0003     SPDX-FileCopyrightText: 1999, 2000 Geert Jansen <jansen@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-only
0006 
0007     stubprocess.cpp: Conversation with kdesu_stub.
0008 */
0009 
0010 #include "stubprocess.h"
0011 #include "kcookie_p.h"
0012 #include "stubprocess_p.h"
0013 
0014 #include <config-kdesu.h>
0015 #include <ksu_debug.h>
0016 
0017 #include <unistd.h>
0018 
0019 extern int kdesuDebugArea();
0020 
0021 namespace KDESu
0022 {
0023 using namespace KDESuPrivate;
0024 
0025 StubProcess::StubProcess()
0026     : StubProcess(*new StubProcessPrivate)
0027 {
0028 }
0029 
0030 StubProcess::StubProcess(StubProcessPrivate &dd)
0031     : PtyProcess(dd)
0032 {
0033     m_user = "root";
0034     m_scheduler = SchedNormal;
0035     m_priority = 50;
0036     m_cookie = new KCookie;
0037     m_XOnly = true;
0038 }
0039 
0040 StubProcess::~StubProcess()
0041 {
0042     delete m_cookie;
0043 }
0044 
0045 void StubProcess::setCommand(const QByteArray &command)
0046 {
0047     m_command = command;
0048 }
0049 
0050 void StubProcess::setUser(const QByteArray &user)
0051 {
0052     m_user = user;
0053 }
0054 
0055 void StubProcess::setXOnly(bool xonly)
0056 {
0057     m_XOnly = xonly;
0058 }
0059 
0060 void StubProcess::setPriority(int prio)
0061 {
0062     if (prio > 100) {
0063         m_priority = 100;
0064     } else if (prio < 0) {
0065         m_priority = 0;
0066     } else {
0067         m_priority = prio;
0068     }
0069 }
0070 
0071 void StubProcess::setScheduler(int sched)
0072 {
0073     m_scheduler = sched;
0074 }
0075 
0076 void StubProcess::writeString(const QByteArray &str)
0077 {
0078     QByteArray out;
0079     out.reserve(str.size() + 8);
0080     for (const uchar c : str) {
0081         if (c < 32) {
0082             out.append('\\');
0083             out.append(c + '@');
0084         } else if (c == '\\') {
0085             out.append('\\');
0086             out.append('/');
0087         } else {
0088             out.append(c);
0089         }
0090     }
0091     writeLine(out);
0092 }
0093 
0094 /*
0095  * Map pid_t to a signed integer type that makes sense for QByteArray;
0096  * only the most common sizes 16 bit and 32 bit are special-cased.
0097  */
0098 template<int T>
0099 struct PIDType {
0100     typedef pid_t PID_t;
0101 };
0102 template<>
0103 struct PIDType<2> {
0104     typedef qint16 PID_t;
0105 };
0106 template<>
0107 struct PIDType<4> {
0108     typedef qint32 PID_t;
0109 };
0110 
0111 /*
0112  * Conversation with kdesu_stub. This is how we pass the authentication
0113  * tokens (X11) and other stuff to kdesu_stub.
0114  * return values: -1 = error, 0 = ok, 1 = kill me
0115  */
0116 
0117 int StubProcess::converseStub(int check)
0118 {
0119     QByteArray line;
0120     QByteArray tmp;
0121 
0122     while (1) {
0123         line = readLine();
0124         if (line.isNull()) {
0125             return -1;
0126         }
0127 
0128         if (line == "kdesu_stub") {
0129             // This makes parsing a lot easier.
0130             enableLocalEcho(false);
0131             if (check) {
0132                 writeLine("stop");
0133             } else {
0134                 writeLine("ok");
0135             }
0136             break;
0137         }
0138     }
0139 
0140     while (1) {
0141         line = readLine();
0142         if (line.isNull()) {
0143             return -1;
0144         }
0145 
0146         if (line == "display") {
0147             writeLine(display());
0148         } else if (line == "display_auth") {
0149 #if HAVE_X11
0150             writeLine(displayAuth());
0151 #else
0152             writeLine("");
0153 #endif
0154         } else if (line == "command") {
0155             writeString(m_command);
0156         } else if (line == "path") {
0157             QByteArray path = qgetenv("PATH");
0158             if (!path.isEmpty() && path[0] == ':') {
0159                 path = path.mid(1);
0160             }
0161             if (m_user == "root") {
0162                 if (!path.isEmpty()) {
0163                     path = "/sbin:/bin:/usr/sbin:/usr/bin:" + path;
0164                 } else {
0165                     path = "/sbin:/bin:/usr/sbin:/usr/bin";
0166                 }
0167             }
0168             writeLine(path);
0169         } else if (line == "user") {
0170             writeLine(m_user);
0171         } else if (line == "priority") {
0172             tmp.setNum(m_priority);
0173             writeLine(tmp);
0174         } else if (line == "scheduler") {
0175             if (m_scheduler == SchedRealtime) {
0176                 writeLine("realtime");
0177             } else {
0178                 writeLine("normal");
0179             }
0180         } else if (line == "xwindows_only") {
0181             if (m_XOnly) {
0182                 writeLine("no");
0183             } else {
0184                 writeLine("yes");
0185             }
0186         } else if (line == "app_startup_id") {
0187             const QList<QByteArray> env = environment();
0188             QByteArray tmp;
0189             static const char startup_env[] = "DESKTOP_STARTUP_ID=";
0190             static const std::size_t size = sizeof(startup_env);
0191             for (const auto &var : env) {
0192                 if (var.startsWith(startup_env)) {
0193                     tmp = var.mid(size - 1);
0194                 }
0195             }
0196             if (tmp.isEmpty()) {
0197                 tmp = "0"; // krazy:exclude=doublequote_chars
0198             }
0199             writeLine(tmp);
0200         } else if (line == "app_start_pid") { // obsolete
0201             // Force the pid_t returned from getpid() into
0202             // something QByteArray understands; avoids ambiguity
0203             // between short and unsigned short in particular.
0204             tmp.setNum((PIDType<sizeof(pid_t)>::PID_t)(getpid()));
0205             writeLine(tmp);
0206         } else if (line == "environment") { // additional env vars
0207             const QList<QByteArray> env = environment();
0208             for (const auto &var : env) {
0209                 writeString(var);
0210             }
0211             writeLine("");
0212         } else if (line == "end") {
0213             return 0;
0214         } else {
0215             qCWarning(KSU_LOG) << "[" << __FILE__ << ":" << __LINE__ << "] "
0216                                << "Unknown request:" << line;
0217             return 1;
0218         }
0219     }
0220 
0221     return 0;
0222 }
0223 
0224 QByteArray StubProcess::display()
0225 {
0226     return m_cookie->display();
0227 }
0228 
0229 QByteArray StubProcess::displayAuth()
0230 {
0231 #if HAVE_X11
0232     return m_cookie->displayAuth();
0233 #else
0234     return QByteArray();
0235 #endif
0236 }
0237 
0238 void StubProcess::virtual_hook(int id, void *data)
0239 {
0240     PtyProcess::virtual_hook(id, data);
0241 }
0242 
0243 } // namespace KDESu