1/*
2 This file is part of the KDE project, module kdesu.
3 SPDX-FileCopyrightText: 1999, 2000 Geert Jansen <jansen@kde.org>
4
5 SPDX-License-Identifier: GPL-2.0-only
6
7 stubprocess.cpp: Conversation with kdesu_stub.
8*/
9
10#include "stubprocess.h"
11#include "kcookie_p.h"
12#include "stubprocess_p.h"
13
14#include <config-kdesu.h>
15#include <ksu_debug.h>
16
17#include <unistd.h>
18
19extern int kdesuDebugArea();
20
21namespace KDESu
22{
23using namespace KDESuPrivate;
24
25StubProcess::StubProcess()
26 : StubProcess(*new StubProcessPrivate)
27{
28}
29
30StubProcess::StubProcess(StubProcessPrivate &dd)
31 : PtyProcess(dd)
32{
33 m_user = "root";
34 m_scheduler = SchedNormal;
35 m_priority = 50;
36 m_cookie = new KCookie;
37 m_XOnly = true;
38}
39
40StubProcess::~StubProcess()
41{
42 delete m_cookie;
43}
44
45void StubProcess::setCommand(const QByteArray &command)
46{
47 m_command = command;
48}
49
50void StubProcess::setUser(const QByteArray &user)
51{
52 m_user = user;
53}
54
55void StubProcess::setXOnly(bool xonly)
56{
57 m_XOnly = xonly;
58}
59
60void StubProcess::setPriority(int prio)
61{
62 if (prio > 100) {
63 m_priority = 100;
64 } else if (prio < 0) {
65 m_priority = 0;
66 } else {
67 m_priority = prio;
68 }
69}
70
71void StubProcess::setScheduler(int sched)
72{
73 m_scheduler = sched;
74}
75
76void StubProcess::writeString(const QByteArray &str)
77{
78 QByteArray out;
79 out.reserve(asize: str.size() + 8);
80 for (const uchar c : str) {
81 if (c < 32) {
82 out.append(c: '\\');
83 out.append(c: c + '@');
84 } else if (c == '\\') {
85 out.append(c: '\\');
86 out.append(c: '/');
87 } else {
88 out.append(c);
89 }
90 }
91 writeLine(line: out);
92}
93
94/*
95 * Map pid_t to a signed integer type that makes sense for QByteArray;
96 * only the most common sizes 16 bit and 32 bit are special-cased.
97 */
98template<int T>
99struct PIDType {
100 typedef pid_t PID_t;
101};
102template<>
103struct PIDType<2> {
104 typedef qint16 PID_t;
105};
106template<>
107struct PIDType<4> {
108 typedef qint32 PID_t;
109};
110
111/*
112 * Conversation with kdesu_stub. This is how we pass the authentication
113 * tokens (X11) and other stuff to kdesu_stub.
114 * return values: -1 = error, 0 = ok, 1 = kill me
115 */
116
117int StubProcess::converseStub(int check)
118{
119 QByteArray line;
120 QByteArray tmp;
121
122 while (1) {
123 line = readLine();
124 if (line.isNull()) {
125 return -1;
126 }
127
128 if (line == "kdesu_stub") {
129 // This makes parsing a lot easier.
130 enableLocalEcho(enable: false);
131 if (check) {
132 writeLine(line: "stop");
133 } else {
134 writeLine(line: "ok");
135 }
136 break;
137 }
138 }
139
140 while (1) {
141 line = readLine();
142 if (line.isNull()) {
143 return -1;
144 }
145
146 if (line == "display") {
147 writeLine(line: display());
148 } else if (line == "display_auth") {
149#if HAVE_X11
150 writeLine(line: displayAuth());
151#else
152 writeLine("");
153#endif
154 } else if (line == "command") {
155 writeString(str: m_command);
156 } else if (line == "path") {
157 QByteArray path = qgetenv(varName: "PATH");
158 if (!path.isEmpty() && path[0] == ':') {
159 path = path.mid(index: 1);
160 }
161 if (m_user == "root") {
162 if (!path.isEmpty()) {
163 path = "/sbin:/bin:/usr/sbin:/usr/bin:" + path;
164 } else {
165 path = "/sbin:/bin:/usr/sbin:/usr/bin";
166 }
167 }
168 writeLine(line: path);
169 } else if (line == "user") {
170 writeLine(line: m_user);
171 } else if (line == "priority") {
172 tmp.setNum(n: m_priority);
173 writeLine(line: tmp);
174 } else if (line == "scheduler") {
175 if (m_scheduler == SchedRealtime) {
176 writeLine(line: "realtime");
177 } else {
178 writeLine(line: "normal");
179 }
180 } else if (line == "xwindows_only") {
181 if (m_XOnly) {
182 writeLine(line: "no");
183 } else {
184 writeLine(line: "yes");
185 }
186 } else if (line == "app_startup_id") {
187 const QList<QByteArray> env = environment();
188 QByteArray tmp;
189 static const char startup_env[] = "DESKTOP_STARTUP_ID=";
190 static const std::size_t size = sizeof(startup_env);
191 for (const auto &var : env) {
192 if (var.startsWith(bv: startup_env)) {
193 tmp = var.mid(index: size - 1);
194 }
195 }
196 if (tmp.isEmpty()) {
197 tmp = "0"; // krazy:exclude=doublequote_chars
198 }
199 writeLine(line: tmp);
200 } else if (line == "app_start_pid") { // obsolete
201 // Force the pid_t returned from getpid() into
202 // something QByteArray understands; avoids ambiguity
203 // between short and unsigned short in particular.
204 tmp.setNum(n: (PIDType<sizeof(pid_t)>::PID_t)(getpid()));
205 writeLine(line: tmp);
206 } else if (line == "environment") { // additional env vars
207 const QList<QByteArray> env = environment();
208 for (const auto &var : env) {
209 writeString(str: var);
210 }
211 writeLine(line: "");
212 } else if (line == "end") {
213 return 0;
214 } else {
215 qCWarning(KSU_LOG) << "[" << __FILE__ << ":" << __LINE__ << "] "
216 << "Unknown request:" << line;
217 return 1;
218 }
219 }
220
221 return 0;
222}
223
224QByteArray StubProcess::display()
225{
226 return m_cookie->display();
227}
228
229QByteArray StubProcess::displayAuth()
230{
231#if HAVE_X11
232 return m_cookie->displayAuth();
233#else
234 return QByteArray();
235#endif
236}
237
238void StubProcess::virtual_hook(int id, void *data)
239{
240 PtyProcess::virtual_hook(id, data);
241}
242
243} // namespace KDESu
244

source code of kdesu/src/stubprocess.cpp