3 * This file is part of the KDE project, module kdesu.
4 * Copyright (C) 1999,2000 Geert Jansen <jansen@kde.org>
6 Permission to use, copy, modify, and distribute this software
7 and its documentation for any purpose and without fee is hereby
8 granted, provided that the above copyright notice appear in all
9 copies and that both that the copyright notice and this
10 permission notice and warranty disclaimer appear in supporting
11 documentation, and that the name of the author not be used in
12 advertising or publicity pertaining to distribution of the
13 software without specific, written prior permission.
15 The author disclaim all warranties with regard to this
16 software, including all implied warranties of merchantability
17 and fitness. In no event shall the author be liable for any
18 special, indirect or consequential damages or any damages
19 whatsoever resulting from loss of use, data or profits, whether
20 in an action of contract, negligence or other tortious action,
21 arising out of or in connection with the use or performance of
24 * passwd.cpp: Change a user's password.
29 #include <config-apps.h> // setenv
41 #include <sys/types.h>
45 #include <kstandarddirs.h>
48 #include <kdesu/process.h>
51 PasswdProcess::PasswdProcess(const QByteArray
&user
)
57 pw
= getpwuid(getuid());
60 kDebug(1512) << "You don't exist!\n";
69 kDebug(1512) << k_lineinfo
<< "User " << user
<< "does not exist.\n";
74 bOtherUser
= (pw
->pw_uid
!= getuid());
78 PasswdProcess::~PasswdProcess()
83 int PasswdProcess::checkCurrent(const char *oldpass
)
85 return exec(oldpass
, 0L, 1);
89 int PasswdProcess::exec(const char *oldpass
, const char *newpass
,
97 // Try to set the default locale to make the parsing of the output
98 // of `passwd' easier.
99 setenv("LANG","C", true /* override */);
101 QList
<QByteArray
> args
;
104 int ret
= KDESu::PtyProcess::exec("passwd", args
);
107 kDebug(1512) << k_lineinfo
<< "Passwd not found!\n";
108 return PasswdNotFound
;
111 ret
= ConversePasswd(oldpass
, newpass
, check
);
113 kDebug(1512) << k_lineinfo
<< "Conversation with passwd failed. pid = " << pid();
115 if ((waitForChild() != 0) && !check
)
116 return PasswordNotGood
;
123 * The tricky thing is to make this work with a lot of different passwd
124 * implementations. We _don't_ want implementation specific routines.
125 * Return values: -1 = unknown error, 0 = ok, >0 = error code.
128 int PasswdProcess::ConversePasswd(const char *oldpass
, const char *newpass
,
131 QByteArray line
, errline
;
142 if (state
== 0 && isPrompt(line
, "new"))
143 // If root is changing a user's password,
144 // passwd can't prompt for the original password.
145 // Therefore, we have to start at state=2.
151 // Eat garbage, wait for prompt
152 m_Error
+= line
+'\n';
153 if (isPrompt(line
, "password"))
156 write(fd(), oldpass
, strlen(oldpass
));
157 write(fd(), "\n", 1);
165 case 1: case 3: case 6:
177 if( line
.contains("again"))
180 kill(m_Pid
, SIGKILL
);
182 return PasswordIncorrect
;
184 // Wait for second prompt.
185 errline
= line
; // use first line for error message
186 while (!isPrompt(line
, "new"))
191 // We didn't get the new prompt so assume incorrect password.
193 fputs(errline
, stdout
);
195 return PasswordIncorrect
;
199 // we have the new prompt
202 kill(m_Pid
, SIGKILL
);
207 write(fd(), newpass
, strlen(newpass
));
208 write(fd(), "\n", 1);
213 // Wait for third prompt
214 if (isPrompt(line
, "re"))
217 write(fd(), newpass
, strlen(newpass
));
218 write(fd(), "\n", 1);
222 // Warning or error about the new password
225 m_Error
= line
+ '\n';
230 // Wait for either a "Reenter password" or a "Enter password" prompt
231 if (isPrompt(line
, "re"))
234 write(fd(), newpass
, strlen(newpass
));
235 write(fd(), "\n", 1);
239 else if (isPrompt(line
, "password"))
241 kill(m_Pid
, SIGKILL
);
243 return PasswordNotGood
;
247 m_Error
+= line
+ '\n';
252 // Are we ok or do we still get an error thrown at us?
260 // No more input... OK
263 if (isPrompt(line
, "password"))
265 // Uh oh, another prompt. Not good!
266 kill(m_Pid
, SIGKILL
);
268 return PasswordNotGood
;
270 m_Error
+= line
+ '\n'; // Collect error message
273 kDebug(1512) << k_lineinfo
<< "Conversation ended successfully.\n";
278 bool PasswdProcess::isPrompt(const QByteArray
&line
, const char *word
)
280 unsigned i
, j
, colon
;
281 unsigned int lineLength(line
.length());
282 for (i
=0,j
=0,colon
=0; i
<lineLength
; i
++)
289 if (!isspace(line
[i
]))
293 if ((colon
!= 1) || (line
[j
] != ':'))
297 return line
.toLower().contains(word
);