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 // Wait for second prompt.
178 errline
= line
; // use first line for error message
179 while (!isPrompt(line
, "new"))
184 // We didn't get the new prompt so assume incorrect password.
186 fputs(errline
, stdout
);
188 return PasswordIncorrect
;
192 // we have the new prompt
195 kill(m_Pid
, SIGKILL
);
200 write(fd(), newpass
, strlen(newpass
));
201 write(fd(), "\n", 1);
206 // Wait for third prompt
207 if (isPrompt(line
, "re"))
210 write(fd(), newpass
, strlen(newpass
));
211 write(fd(), "\n", 1);
215 // Warning or error about the new password
218 m_Error
= line
+ '\n';
223 // Wait for either a "Reenter password" or a "Enter password" prompt
224 if (isPrompt(line
, "re"))
227 write(fd(), newpass
, strlen(newpass
));
228 write(fd(), "\n", 1);
232 else if (isPrompt(line
, "password"))
234 kill(m_Pid
, SIGKILL
);
236 return PasswordNotGood
;
240 m_Error
+= line
+ '\n';
245 // Are we ok or do we still get an error thrown at us?
253 // No more input... OK
256 if (isPrompt(line
, "password"))
258 // Uh oh, another prompt. Not good!
259 kill(m_Pid
, SIGKILL
);
261 return PasswordNotGood
;
263 m_Error
+= line
+ '\n'; // Collect error message
266 kDebug(1512) << k_lineinfo
<< "Conversation ended successfully.\n";
271 bool PasswdProcess::isPrompt(const QByteArray
&line
, const char *word
)
273 unsigned i
, j
, colon
;
274 unsigned int lineLength(line
.length());
275 for (i
=0,j
=0,colon
=0; i
<lineLength
; i
++)
282 if (!isspace(line
[i
]))
286 if ((colon
!= 1) || (line
[j
] != ':'))
290 return line
.toLower().contains(word
);