2 * Copyright (c) 1998 Denis Perchine <dyp@perchine.com>
3 * Copyright (c) 2004 Szombathelyi GyĂśrgy <gyurco@freemail.hu>
4 * Former maintainer: Adriaan de Groot <groot@kde.org>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 #include <ku_config.h>
29 #include <sys/types.h>
39 #include <kstandarddirs.h>
40 #include <kmessagebox.h>
44 #include "ku_userfiles.h"
48 KU_UserFiles::KU_UserFiles(KU_PrefsBase
*cfg
) : KU_Users( cfg
)
63 if ( !mCfg
->shadowsrc().isEmpty() ) caps
|= Cap_Shadow
;
65 #if defined(__FreeBSD__) || defined(__bsdi__)
70 KU_UserFiles::~KU_UserFiles()
74 bool KU_UserFiles::reload() {
75 mErrorString
= mErrorDetails
= QString();
88 bool KU_UserFiles::loadpwd()
92 QString passwd_filename
;
96 // Read KUser configuration
98 passwd_filename
= mCfg
->passwdsrc();
100 // Handle unconfigured environments
102 if( passwd_filename
.isEmpty() ) {
103 mErrorString
= i18n("KUser sources were not configured.\nSet 'Password file' in Settings/Files");
107 // Start reading passwd file
109 rc
= stat(QFile::encodeName(passwd_filename
), &st
);
111 mErrorString
+= i18n("Stat call on file %1 failed: %2\nCheck KUser settings.", passwd_filename
, QString::fromLocal8Bit(strerror(errno
)));
115 pwd_mode
= st
.st_mode
& 0666;
119 // We are reading our configuration specified passwd file
122 #ifdef HAVE_FGETPWENT
123 FILE *fpwd
= fopen(QFile::encodeName(passwd_filename
), "r");
125 mErrorString
+= i18n("Error opening %1 for reading.\n", passwd_filename
);
129 while ((p
= fgetpwent(fpwd
)) != NULL
) {
131 setpwent(); //This should be enough for BSDs
132 while ((p
= getpwent()) != NULL
) {
135 user
.setCaps( KU_User::Cap_POSIX
);
136 user
.setUID(p
->pw_uid
);
137 user
.setGID(p
->pw_gid
);
138 user
.setName(QString::fromLocal8Bit(p
->pw_name
));
139 tmp
= QString::fromLocal8Bit( p
->pw_passwd
);
140 if ( tmp
!= "x" && tmp
!= "*" && !tmp
.startsWith('!') )
141 user
.setDisabled( false );
143 user
.setDisabled( true );
144 if ( tmp
.startsWith('!') ) tmp
.remove(0, 1);
146 user
.setHomeDir(QString::fromLocal8Bit(p
->pw_dir
));
147 user
.setShell(QString::fromLocal8Bit(p
->pw_shell
));
148 #if defined(__FreeBSD__) || defined(__bsdi__)
149 user
.setClass(QString::fromLatin1(p
->pw_class
));
150 user
.setLastChange(p
->pw_change
);
151 user
.setExpire(p
->pw_expire
);
154 if ((p
->pw_gecos
!= 0) && (p
->pw_gecos
[0] != 0))
155 fillGecos(user
, p
->pw_gecos
);
157 kDebug() << "added: " << user
.getName();
160 // End reading passwd_filename
162 #ifdef HAVE_FGETPWENT
171 // Load shadow passwords
173 bool KU_UserFiles::loadsdw()
176 QString shadow_file
,tmp
;
182 shadow_file
= mCfg
->shadowsrc();
183 if ( shadow_file
.isEmpty() )
186 stat( QFile::encodeName(shadow_file
), &st
);
187 sdw_mode
= st
.st_mode
& 0666;
191 #ifdef HAVE_FGETSPENT
193 kDebug() << "open shadow file: " << shadow_file
;
194 if ((f
= fopen( QFile::encodeName(shadow_file
), "r")) == NULL
) {
195 KMessageBox::error( 0, i18n("Error opening %1 for reading.", shadow_file
) );
199 while ((spw
= fgetspent( f
))) { // read a shadow password structure
202 while ((spw
= getspent())) { // read a shadow password structure
205 kDebug() << "shadow entry: " << spw
->sp_namp
;
206 if ((index
= lookup(QString::fromLocal8Bit(spw
->sp_namp
))) == -1) {
207 KMessageBox::error( 0, i18n("No /etc/passwd entry for %1.\nEntry will be removed at the next `Save'-operation.", QString::fromLocal8Bit(spw
->sp_namp
)) );
212 tmp
= QString::fromLocal8Bit( spw
->sp_pwdp
);
213 if ( tmp
.startsWith("!!") || tmp
== "*" ) {
214 user
.setDisabled( true );
217 user
.setDisabled( false );
219 user
.setSPwd( tmp
); // cp the encrypted pwd
220 user
.setLastChange( daysToTime( spw
->sp_lstchg
) );
221 user
.setMin(spw
->sp_min
);
222 user
.setMax(spw
->sp_max
);
224 user
.setWarn(spw
->sp_warn
);
225 user
.setInactive(spw
->sp_inact
);
226 user
.setExpire( daysToTime( spw
->sp_expire
) );
227 user
.setFlag(spw
->sp_flag
);
229 replace( index
, user
);
232 #ifdef HAVE_FGETSPENT
238 #endif // HAVE_SHADOW_H
243 // Save password file
245 #define escstr(a) tmp2 = user.get##a(); \
246 tmp2.replace(':',"_"); \
247 tmp2.replace(',',"_"); \
251 bool KU_UserFiles::savepwd()
253 FILE *passwd_fd
= NULL
;
254 FILE *shadow_fd
= NULL
;
259 QString passwd_filename
;
260 QString shadow_filename
;
261 bool write_shadow
= false;
264 shadow_filename
= mCfg
->shadowsrc();
265 if ( !shadow_filename
.isEmpty() && (caps
& Cap_Shadow
) ) write_shadow
= true;
268 // Read KU_User configuration info
270 passwd_filename
= mCfg
->passwdsrc();
271 QString new_passwd_filename
=
272 passwd_filename
+ QString::fromLatin1(KU_CREATE_EXT
);
273 QString new_shadow_filename
=
274 shadow_filename
+ QString::fromLatin1(KU_CREATE_EXT
);
278 if ( write_shadow
) {
280 if (!backup(shadow_filename
)) return false;
285 if(!passwd_filename
.isEmpty()) {
287 if (!backup(passwd_filename
)) return false;
293 if ((shadow_fd
= fopen(QFile::encodeName(new_shadow_filename
), "w")) == NULL
) {
294 mErrorString
= i18n("Error opening %1 for writing.", new_shadow_filename
);
298 if(!passwd_filename
.isEmpty()) {
300 fopen(QFile::encodeName(new_passwd_filename
),"w")) == NULL
) {
301 mErrorString
= i18n("Error opening %1 for writing.", passwd_filename
);
308 int usersindex
= 0, addindex
= 0;
310 spwd
.sp_namp
= (char *)malloc(200);
311 spwd
.sp_pwdp
= (char *)malloc(200);
315 if ( usersindex
== count() ) {
316 if ( addindex
== mAdd
.count() ) break;
317 user
= mAdd
.at( addindex
);
320 if ( mDel
.contains( usersindex
) ) {
324 if ( mMod
.contains( usersindex
) ) {
325 user
= mMod
.value( usersindex
);
327 user
= at( usersindex
);
332 tmp_uid
= user
.getUID();
333 if ( caps
& Cap_Shadow
)
337 if ( user
.getDisabled() && tmp
!= "x" && tmp
!= "*" )
346 #if defined(__FreeBSD__) || defined(__bsdi__)
352 user
.getName() + ':' +
354 QString::number( user
.getUID() ) + ':' +
355 QString::number( user
.getGID() ) + ':' +
356 user
.getClass() + ':' +
357 QString::number( user
.getLastChange() ) + ':' +
358 QString::number( user
.getExpire() ) + ':';
361 user
.getFullName() + ',' +
362 user
.getOffice() + ',' +
363 user
.getWorkPhone() + ',' +
370 user
.getName() + ':' +
372 QString::number( user
.getUID() ) + ':' +
373 QString::number( user
.getGID() ) + ':';
376 user
.getFullName() + ',' +
377 user
.getOffice1() + ',' +
378 user
.getOffice2() + ',' +
382 for (int j
=(s1
.length()-1); j
>=0; j
--) {
389 user
.getHomeDir() + ':' +
390 user
.getShell() + '\n';
393 if ( write_shadow
) {
394 strncpy( spwd
.sp_namp
, user
.getName().toLocal8Bit(), 200 );
395 if ( user
.getDisabled() )
396 strncpy( spwd
.sp_pwdp
, QString("!!" + user
.getSPwd()).toLocal8Bit(), 200 );
398 strncpy( spwd
.sp_pwdp
, user
.getSPwd().toLocal8Bit(), 200 );
400 spwd
.sp_lstchg
= timeToDays( user
.getLastChange() );
401 spwd
.sp_min
= user
.getMin();
402 spwd
.sp_max
= user
.getMax();
404 spwd
.sp_warn
= user
.getWarn();
405 spwd
.sp_inact
= user
.getInactive();
406 spwd
.sp_expire
= timeToDays( user
.getExpire() );
407 spwd
.sp_flag
= user
.getFlag();
409 putspent(&spwd
, shadow_fd
);
413 fputs(s
.toLocal8Bit().data(), passwd_fd
);
418 chmod(QFile::encodeName(new_passwd_filename
), pwd_mode
);
419 chown(QFile::encodeName(new_passwd_filename
), pwd_uid
, pwd_gid
);
420 rename(QFile::encodeName(new_passwd_filename
),
421 QFile::encodeName(passwd_filename
));
426 chmod(QFile::encodeName(new_shadow_filename
), sdw_mode
);
427 chown(QFile::encodeName(new_shadow_filename
), sdw_uid
, sdw_gid
);
428 rename(QFile::encodeName(new_shadow_filename
),
429 QFile::encodeName(shadow_filename
));
433 ::free(spwd
.sp_namp
);
434 ::free(spwd
.sp_pwdp
);
437 // need to run a utility program to build /etc/passwd, /etc/pwd.db
438 // and /etc/spwd.db from /etc/master.passwd
439 #if defined(__FreeBSD__) || defined(__bsdi__)
440 if (system(PWMKDB
) != 0) {
441 mErrorString
= i18n("Unable to build password database.");
451 // Save shadow passwords file
453 void KU_UserFiles::createPassword( KU_User
&user
, const QString
&password
)
455 if ( caps
& Cap_Shadow
) {
456 user
.setSPwd( encryptPass( password
, mCfg
->md5shadow() ) );
457 user
.setPwd( QString::fromLatin1("x") );
459 user
.setPwd( encryptPass( password
, false ) );
462 bool KU_UserFiles::dbcommit()
467 mErrorString
= mErrorDetails
= QString();
471 if ( mDel
.isEmpty() && mAdd
.isEmpty() && mMod
.isEmpty() )
477 if ( !ret
) return false;