• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KDEsu

  • sources
  • kde-4.12
  • kdelibs
  • kdesu
su.cpp
Go to the documentation of this file.
1 /* vi: ts=8 sts=4 sw=4
2 *
3 * This file is part of the KDE project, module kdesu.
4 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
5 *
6 * Sudo support added by Jonathan Riddell <jriddell@ ubuntu.com>
7 * Copyright (C) 2005 Canonical Ltd // krazy:exclude=copyright (no email)
8 *
9 * This is free software; you can use this library under the GNU Library
10 * General Public License, version 2. See the file "COPYING.LIB" for the
11 * exact licensing terms.
12 *
13 * su.cpp: Execute a program as another user with "class SuProcess".
14 */
15 
16 #include "su.h"
17 #include "kcookie.h"
18 
19 #include <config.h>
20 #include <config-prefix.h> // for LIBEXEC_INSTALL_DIR
21 
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <unistd.h>
25 #include <fcntl.h>
26 #include <errno.h>
27 #include <string.h>
28 #include <ctype.h>
29 #include <signal.h>
30 
31 #include <sys/types.h>
32 #include <sys/stat.h>
33 
34 #include <QtCore/QFile>
35 
36 #include <kconfig.h>
37 #include <kconfiggroup.h>
38 #include <kdebug.h>
39 #include <klocale.h>
40 #include <kstandarddirs.h>
41 #include <kuser.h>
42 
43 int kdesuDebugArea()
44 {
45  static int s_area = KDebug::registerArea("kdesu (kdelibs)");
46  return s_area;
47 }
48 
49 #ifndef __PATH_SU
50 #define __PATH_SU "false"
51 #endif
52 
53 #ifndef __PATH_SUDO
54 #define __PATH_SUDO "false"
55 #endif
56 
57 #ifdef KDESU_USE_SUDO_DEFAULT
58 # define DEFAULT_SUPER_USER_COMMAND "sudo"
59 #else
60 # define DEFAULT_SUPER_USER_COMMAND "su"
61 #endif
62 
63 namespace KDESu {
64 using namespace KDESuPrivate;
65 
66 class SuProcess::SuProcessPrivate
67 {
68 public:
69  QString m_superUserCommand;
70 };
71 
72 SuProcess::SuProcess(const QByteArray &user, const QByteArray &command)
73  : d( new SuProcessPrivate )
74 {
75  m_User = user;
76  m_Command = command;
77 
78  KSharedConfig::Ptr config = KGlobal::config();
79  KConfigGroup group(config, "super-user-command");
80  d->m_superUserCommand = group.readEntry("super-user-command", DEFAULT_SUPER_USER_COMMAND);
81 
82  if ( d->m_superUserCommand != "sudo" && d->m_superUserCommand != "su" ) {
83  kWarning() << "unknown super user command.";
84  d->m_superUserCommand = DEFAULT_SUPER_USER_COMMAND;
85  }
86 }
87 
88 
89 SuProcess::~SuProcess()
90 {
91  delete d;
92 }
93 
94 QString SuProcess::superUserCommand()
95 {
96  return d->m_superUserCommand;
97 }
98 
99 bool SuProcess::useUsersOwnPassword()
100 {
101  if (superUserCommand() == "sudo" && m_User == "root") {
102  return true;
103  }
104 
105  KUser user;
106  return user.loginName() == m_User;
107 }
108 
109 int SuProcess::checkInstall(const char *password)
110 {
111  return exec(password, Install);
112 }
113 
114 int SuProcess::checkNeedPassword()
115 {
116  return exec(0L, NeedPassword);
117 }
118 
119 /*
120 * Execute a command with su(1).
121 */
122 
123 int SuProcess::exec(const char *password, int check)
124 {
125  if (check)
126  setTerminal(true);
127 
128  // since user may change after constructor (due to setUser())
129  // we need to override sudo with su for non-root here
130  if (m_User != "root") {
131  d->m_superUserCommand = "su";
132  }
133 
134  QList<QByteArray> args;
135  if (d->m_superUserCommand == "sudo") {
136  args += "-u";
137  }
138 
139  if ((m_Scheduler != SchedNormal) || (m_Priority > 50))
140  args += "root";
141  else
142  args += m_User;
143 
144  if (d->m_superUserCommand == "su") {
145  args += "-c";
146  }
147  args += QByteArray(LIBEXEC_INSTALL_DIR) + "/kdesu_stub";
148  args += "-"; // krazy:exclude=doublequote_chars (QList, not QString)
149 
150  QByteArray command;
151  if (d->m_superUserCommand == "sudo") {
152  command = __PATH_SUDO;
153  } else {
154  command = __PATH_SU;
155  }
156 
157  if (::access(command, X_OK) != 0)
158  {
159  command = QFile::encodeName( KGlobal::dirs()->findExe(d->m_superUserCommand.toLatin1()) );
160  if (command.isEmpty())
161  return check ? SuNotFound : -1;
162  }
163 
164  // kDebug(kdesuDebugArea()) << k_lineinfo << "Call StubProcess::exec()";
165  if (StubProcess::exec(command, args) < 0)
166  {
167  return check ? SuNotFound : -1;
168  }
169  // kDebug(kdesuDebugArea()) << k_lineinfo << "Done StubProcess::exec()";
170 
171  SuErrors ret = (SuErrors) ConverseSU(password);
172  // kDebug(kdesuDebugArea()) << k_lineinfo << "Conversation returned" << ret;
173 
174  if (ret == error)
175  {
176  if (!check)
177  kError(kdesuDebugArea()) << k_lineinfo << "Conversation with su failed.";
178  return ret;
179  }
180  if (check == NeedPassword)
181  {
182  if (ret == killme)
183  {
184  if ( d->m_superUserCommand == "sudo" ) {
185  // sudo can not be killed, just return
186  return ret;
187  }
188  if (kill(m_Pid, SIGKILL) < 0) {
189  kDebug() << "kill < 0";
190  //FIXME SIGKILL doesn't work for sudo,
191  //why is this different from su?
192  //A: because sudo runs as root. Perhaps we could write a Ctrl+C to its stdin, instead?
193  ret=error;
194  }
195  else
196  {
197  int iret = waitForChild();
198  if (iret < 0) ret=error;
199  else /* nothing */ {} ;
200  }
201  }
202  return ret;
203  }
204 
205  if (m_bErase && password)
206  memset(const_cast<char *>(password), 0, qstrlen(password));
207 
208  if (ret != ok)
209  {
210  kill(m_Pid, SIGKILL);
211  if (d->m_superUserCommand != "sudo") {
212  waitForChild();
213  }
214  return SuIncorrectPassword;
215  }
216 
217  int iret = ConverseStub(check);
218  if (iret < 0)
219  {
220  if (!check)
221  kError(kdesuDebugArea()) << k_lineinfo << "Conversation with kdesu_stub failed.";
222  return iret;
223  }
224  else if (iret == 1)
225  {
226  kill(m_Pid, SIGKILL);
227  waitForChild();
228  return SuIncorrectPassword;
229  }
230 
231  if (check == Install)
232  {
233  waitForChild();
234  return 0;
235  }
236 
237  iret = waitForChild();
238  return iret;
239 }
240 
241 /*
242 * Conversation with su: feed the password.
243 * Return values: -1 = error, 0 = ok, 1 = kill me, 2 not authorized
244 */
245 
246 int SuProcess::ConverseSU(const char *password)
247 {
248  enum { WaitForPrompt, CheckStar, HandleStub } state = WaitForPrompt;
249  int colon;
250  unsigned i, j;
251  // kDebug(kdesuDebugArea()) << k_lineinfo << "ConverseSU starting.";
252 
253  QByteArray line;
254  while (true)
255  {
256  line = readLine();
257  if (line.isNull())
258  return ( state == HandleStub ? notauthorized : error);
259  kDebug(kdesuDebugArea()) << k_lineinfo << "Read line" << line;
260 
261  if (line == "kdesu_stub")
262  {
263  unreadLine(line);
264  return ok;
265  }
266 
267  switch (state)
268  {
270  case WaitForPrompt:
271  {
272  if (waitMS(fd(),100)>0)
273  {
274  // There is more output available, so this line
275  // couldn't have been a password prompt (the definition
276  // of prompt being that there's a line of output followed
277  // by a colon, and then the process waits).
278  continue;
279  }
280 
281  // Match "Password: " with the regex ^[^:]+:[\w]*$.
282  const uint len = line.length();
283  for (i=0,j=0,colon=0; i<len; ++i)
284  {
285  if (line[i] == ':')
286  {
287  j = i; colon++;
288  continue;
289  }
290  if (!isspace(line[i]))
291  j++;
292  }
293  if ((colon == 1) && (line[j] == ':'))
294  {
295  if (password == 0L)
296  return killme;
297  if (WaitSlave())
298  return error;
299  write(fd(), password, strlen(password));
300  write(fd(), "\n", 1);
301  state = CheckStar;
302  }
303  break;
304  }
306  case CheckStar:
307  {
308  QByteArray s = line.trimmed();
309  if (s.isEmpty())
310  {
311  state=HandleStub;
312  break;
313  }
314  const uint len = line.length();
315  for (i=0; i< len; ++i)
316  {
317  if (s[i] != '*')
318  return error;
319  }
320  state=HandleStub;
321  break;
322  }
324  case HandleStub:
325  break;
327  } // end switch
328  } // end while (true)
329  return ok;
330 }
331 
332 void SuProcess::virtual_hook( int id, void* data )
333 { StubProcess::virtual_hook( id, data ); }
334 
335 }
KDESu::SuProcess::SuNotFound
Definition: su.h:31
KSharedPtr< KSharedConfig >
kuser.h
kcookie.h
KDESu::StubProcess::m_Priority
int m_Priority
Definition: stub.h:90
kdebug.h
group
__PATH_SUDO
#define __PATH_SUDO
Definition: su.cpp:54
KDESu::PtyProcess::readLine
QByteArray readLine(bool block=true)
Reads a line from the program's standard out.
Definition: process.cpp:239
kconfig.h
KGlobal::dirs
KStandardDirs * dirs()
kError
static QDebug kError(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KDESu::PtyProcess::waitForChild
int waitForChild()
Waits for the child to exit.
Definition: process.cpp:430
kdesuDebugArea
int kdesuDebugArea()
Definition: su.cpp:43
QString
kDebug
static QDebug kDebug(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
klocale.h
config
KSharedConfigPtr config()
KUser
KDESu::PtyProcess::m_Pid
int m_Pid
PID of child process.
Definition: process.h:185
KDESu::StubProcess::m_User
QByteArray m_User
Definition: stub.h:93
KDESu::SuProcess::checkNeedPassword
int checkNeedPassword()
Checks if a password is needed.
Definition: su.cpp:114
KDESu::StubProcess::m_Command
QByteArray m_Command
Definition: stub.h:92
KDESu::SuProcess::exec
int exec(const char *password, int check=NoCheck)
Definition: su.cpp:123
KDESu::StubProcess::ConverseStub
int ConverseStub(int check)
Exchange all parameters with kdesu_stub.
Definition: stub.cpp:125
KUser::loginName
QString loginName() const
KDESu::PtyProcess::m_bErase
bool m_bErase
Definition: process.h:181
isspace
#define isspace(c)
KDebug::registerArea
static int registerArea(const QByteArray &areaName, bool enabled=true)
KDESu::SuProcess::superUserCommand
QString superUserCommand()
Checks what the default super user command is, e.g.
Definition: su.cpp:94
KDESu::SuProcess::Install
Definition: su.h:36
KDESu::SuProcess::~SuProcess
~SuProcess()
Definition: su.cpp:89
__PATH_SU
#define __PATH_SU
Definition: su.cpp:50
KDESu::SuProcess::checkInstall
int checkInstall(const char *password)
Checks if the stub is installed and the password is correct.
Definition: su.cpp:109
KDESu::SuProcess::SuProcess
SuProcess(const QByteArray &user=0, const QByteArray &command=0)
Definition: su.cpp:72
KDESu::PtyProcess::exec
int exec(const QByteArray &command, const QList< QByteArray > &args)
Forks off and execute a command.
Definition: process.cpp:291
KDESu::StubProcess::virtual_hook
virtual void virtual_hook(int id, void *data)
Standard hack to add virtual methods in a BC way.
Definition: stub.cpp:233
KConfigGroup
KDESu::PtyProcess::WaitSlave
int WaitSlave()
Waits until the pty has cleared the ECHO flag.
Definition: process.cpp:377
KDESu::SuProcess::SuIncorrectPassword
Definition: su.h:31
access
int access(const QString &path, int mode)
kstandarddirs.h
KDESu::PtyProcess::unreadLine
void unreadLine(const QByteArray &line, bool addNewline=true)
Puts back a line of input.
Definition: process.cpp:273
DEFAULT_SUPER_USER_COMMAND
#define DEFAULT_SUPER_USER_COMMAND
Definition: su.cpp:60
KDESu::SuProcess::useUsersOwnPassword
bool useUsersOwnPassword()
Checks whether or not the user's password is being asked for or another user's password.
Definition: su.cpp:99
kWarning
static QDebug kWarning(bool cond, int area=KDE_DEFAULT_DEBUG_AREA)
KDESu::SuProcess::NeedPassword
Definition: su.h:36
su.h
KDESu::StubProcess::SchedNormal
Definition: stub.h:64
KDESu::StubProcess::m_Scheduler
int m_Scheduler
Definition: stub.h:91
KDESu::SuProcess::virtual_hook
virtual void virtual_hook(int id, void *data)
Standard hack to add virtual methods in a BC way.
Definition: su.cpp:332
KDESu::PtyProcess::fd
int fd() const
Returns the filedescriptor of the process.
Definition: process.cpp:170
k_lineinfo
#define k_lineinfo
KConfigGroup::readEntry
T readEntry(const QString &key, const T &aDefault) const
kconfiggroup.h
QList< QByteArray >
KDESu::PtyProcess::setTerminal
void setTerminal(bool terminal)
Enables/disables terminal output.
Definition: process.cpp:412
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:49:48 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KDEsu

Skip menu "KDEsu"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal