• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdesu
 

tdesu

  • tdesu
su.cpp
1 /*
2 *
3 * $Id$
4 *
5 * This file is part of the KDE project, module tdesu.
6 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
7 *
8 * Sudo support added by Jonathan Riddell <jriddell@ ubuntu.com>
9 * Copyright (C) 2005 Canonical Ltd
10 *
11 * This is free software; you can use this library under the GNU Library
12 * General Public License, version 2. See the file "COPYING.LIB" for the
13 * exact licensing terms.
14 *
15 * su.cpp: Execute a program as another user with "class SuProcess".
16 */
17 
18 #include <config.h>
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <ctype.h>
27 #include <signal.h>
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 
32 #include <tqglobal.h>
33 #include <tqcstring.h>
34 #include <tqfile.h>
35 
36 #include <tdeconfig.h>
37 #include <kdebug.h>
38 #include <tdelocale.h>
39 #include <kstandarddirs.h>
40 
41 #include "su.h"
42 #include "kcookie.h"
43 
44 
45 #ifndef __PATH_SU
46 #define __PATH_SU "false"
47 #endif
48 
49 #ifndef __PATH_SUDO
50 #define __PATH_SUDO "false"
51 #endif
52 
53 SuProcess::SuProcess(const TQCString &user, const TQCString &command)
54 {
55  m_User = user;
56  m_Command = command;
57 
58  TDEConfig* config = TDEGlobal::config();
59  config->setGroup("super-user-command");
60  superUserCommand = config->readEntry("super-user-command", DEFAULT_SUPER_USER_COMMAND);
61  if ( superUserCommand != "sudo" && superUserCommand != "su" ) {
62  kdWarning() << "unknown super user command" << endl;
63  superUserCommand = "su";
64  }
65 }
66 
67 
68 SuProcess::~SuProcess()
69 {
70 }
71 
72 int SuProcess::checkInstall(const char *password)
73 {
74  return exec(password, Install);
75 }
76 
77 int SuProcess::checkNeedPassword()
78 {
79  return exec(0L, NeedPassword);
80 }
81 
82 /*
83 * Execute a command with su(1).
84 */
85 
86 int SuProcess::exec(const char *password, int check)
87 {
88  if (check)
89  setTerminal(true);
90 
91  // since user may change after constructor (due to setUser())
92  // we need to override sudo with su for non-root here
93  if (m_User != "root") {
94  superUserCommand = "su";
95  }
96 
97  QCStringList args;
98  if (superUserCommand == "sudo") {
99  args += "-u";
100  }
101 
102 #ifdef Q_OS_DARWIN
103  args += "-c";
104  args += "staff";
105 #endif
106 
107  if ((m_Scheduler != SchedNormal) || (m_Priority > 50))
108  args += "root";
109  else
110  args += m_User;
111 
112  if (superUserCommand == "su") {
113  args += "-c";
114  }
115  args += TQCString(__TDE_BINDIR) + "/tdesu_stub";
116 #ifndef Q_OS_DARWIN
117  args += "-";
118 #endif
119 
122  TQCString command;
123  if (superUserCommand == "sudo") {
124  command = __PATH_SUDO;
125  } else {
126  command = __PATH_SU;
127  }
128 
129  if (::access(command, X_OK) != 0)
130  {
132  command = TQFile::encodeName( TDEGlobal::dirs()->findExe(superUserCommand.ascii()) );
133  if (command.isEmpty())
134  return check ? SuNotFound : -1;
135  }
136 
137  // kdDebug(900) << k_lineinfo << "Call StubProcess::exec()" << endl;
138  if (StubProcess::exec(command, args) < 0)
139  {
140  return check ? SuNotFound : -1;
141  }
142  // kdDebug(900) << k_lineinfo << "Done StubProcess::exec()" << endl;
143 
144  SuErrors ret = (SuErrors) ConverseSU(password);
145  // kdDebug(900) << k_lineinfo << "Conversation returned " << ret << endl;
146 
147  if (ret == error)
148  {
149  if (!check)
150  kdError(900) << k_lineinfo << "Conversation with " << superUserCommand << " failed\n";
151  return ret;
152  }
153  if (check == NeedPassword)
154  {
155  if (ret == killme)
156  {
161  if ( superUserCommand == "sudo" ) {
162  // sudo can not be killed, just return
163  return ret;
164  }
165  if (kill(m_Pid, SIGKILL) < 0) {
166  kdDebug() << k_funcinfo << "kill < 0" << endl;
167  //FIXME SIGKILL doesn't work for sudo,
168  //why is this different from su?
169  ret=error;
170  }
171  else
172  {
173  int iret = waitForChild();
174  if (iret < 0) ret=error;
175  else /* nothing */ {} ;
176  }
177  }
178  return ret;
179  }
180 
181  if (m_bErase && password)
182  {
183  char *ptr = const_cast<char *>(password);
184  const uint plen = strlen(password);
185  for (unsigned i=0; i < plen; i++)
186  ptr[i] = '\000';
187  }
188 
189  if (ret == notauthorized)
190  {
191  kill(m_Pid, SIGKILL);
192  if (superUserCommand != "sudo") {
193  waitForChild();
194  }
195  return SuIncorrectPassword;
196  }
197 
198  int iret = ConverseStub(check);
199  if (iret < 0)
200  {
201  if (!check)
202  kdError(900) << k_lineinfo << "Converstation with tdesu_stub failed\n";
203  return iret;
204  }
205  else if (iret == 1)
206  {
207  kill(m_Pid, SIGKILL);
208  waitForChild();
209  return SuIncorrectPassword;
210  }
211 
212  if (check == Install)
213  {
214  waitForChild();
215  return 0;
216  }
217 
218  iret = waitForChild();
219  return iret;
220 }
221 
222 /*
223 * Conversation with su: feed the password.
224 * Return values: -1 = error, 0 = ok, 1 = kill me, 2 not authorized
225 */
226 
227 int SuProcess::ConverseSU(const char *password)
228 {
229  enum { WaitForPrompt, CheckStar, HandleStub } state = WaitForPrompt;
230  int colon;
231  unsigned i, j;
232  // kdDebug(900) << k_lineinfo << "ConverseSU starting." << endl;
233 
234  TQCString line;
235  while (true)
236  {
237  line = readLine();
238  if (line.isNull())
239  return ( state == HandleStub ? notauthorized : error);
240  kdDebug(900) << k_lineinfo << "Read line <" << line << ">" << endl;
241 
242  switch (state)
243  {
245  case WaitForPrompt:
246  {
247  // In case no password is needed.
248  if (line == "tdesu_stub")
249  {
250  unreadLine(line);
251  return ok;
252  }
253 
254  while(waitMS(m_Fd,100)>0)
255  {
256  // There is more output available, so the previous line
257  // couldn't have been a password prompt (the definition
258  // of prompt being that there's a line of output followed
259  // by a colon, and then the process waits).
260  TQCString more = readLine();
261  if (more.isEmpty())
262  break;
263 
264  line = more;
265  kdDebug(900) << k_lineinfo << "Read line <" << more << ">" << endl;
266  }
267 
268  // Match "Password: " with the regex ^[^:]+:[\w]*$.
269  const uint len = line.length();
270  for (i=0,j=0,colon=0; i<len; i++)
271  {
272  if (line[i] == ':')
273  {
274  j = i; colon++;
275  continue;
276  }
277  if (!isspace(line[i]))
278  j++;
279  }
280  if ((colon == 1) && (line[j] == ':'))
281  {
282  if (password == 0L)
283  return killme;
284  if (!checkPid(m_Pid))
285  {
286  kdError(900) << superUserCommand << " has exited while waiting for pwd." << endl;
287  return error;
288  }
289  if ((WaitSlave() == 0) && checkPid(m_Pid))
290  {
291  write(m_Fd, password, strlen(password));
292  write(m_Fd, "\n", 1);
293  state=CheckStar;
294  }
295  else
296  {
297  return error;
298  }
299  }
300  break;
301  }
303  case CheckStar:
304  {
305  TQCString s = line.stripWhiteSpace();
306  if (s.isEmpty())
307  {
308  state=HandleStub;
309  break;
310  }
311  const uint len = line.length();
312  for (i=0; i< len; i++)
313  {
314  if (s[i] != '*')
315  return error;
316  }
317  state=HandleStub;
318  break;
319  }
321  case HandleStub:
322  // Read till we get "tdesu_stub"
323  if (line == "tdesu_stub")
324  {
325  unreadLine(line);
326  return ok;
327  } else if (superUserCommand == "sudo") {
328  // sudo gives a "sorry" line so reaches here
329  // with the wrong password
330  return notauthorized;
331  }
332  break;
334  } // end switch
335  } // end while (true)
336  return ok;
337 }
338 
339 void SuProcess::virtual_hook( int id, void* data )
340 { StubProcess::virtual_hook( id, data ); }
341 
342 
SuProcess::checkInstall
int checkInstall(const char *password)
Checks if the stub is installed and the password is correct.
Definition: su.cpp:72
PtyProcess::waitForChild
int waitForChild()
Waits for the child to exit.
Definition: process.cpp:486
SuProcess::checkNeedPassword
int checkNeedPassword()
Checks if a password is needed.
Definition: su.cpp:77
PtyProcess::WaitSlave
int WaitSlave()
Waits until the pty has cleared the ECHO flag.
Definition: process.cpp:412
PtyProcess::exec
int exec(const TQCString &command, const QCStringList &args)
Forks off and execute a command.
Definition: process.cpp:324
PtyProcess::unreadLine
void unreadLine(const TQCString &line, bool addNewline=true)
Puts back a line of input.
Definition: process.cpp:311
PtyProcess::readLine
TQCString readLine(bool block=true)
Reads a line from the program's standard out.
Definition: process.cpp:175
PtyProcess::checkPid
static bool checkPid(pid_t pid)
Basic check for the existence of pid.
Definition: process.cpp:75
PtyProcess::setTerminal
void setTerminal(bool terminal)
Enables/disables terminal output.
Definition: process.h:105
PtyProcess::waitMS
static int waitMS(int fd, int ms)
Wait ms miliseconds (ie.
Definition: process.cpp:59
SuProcess::exec
int exec(const char *password, int check=NoCheck)
Definition: su.cpp:86
StubProcess::ConverseStub
int ConverseStub(int check)
Exchange all parameters with tdesu_stub.
Definition: stub.cpp:80

tdesu

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

tdesu

Skip menu "tdesu"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdesu by doxygen 1.8.8
This website is maintained by Timothy Pearson.