source: src-qt4/pc-usermanager/usermanagerback.cpp @ f416e9b

9.2-releasereleng/10.0releng/10.0.1releng/10.0.2releng/10.0.3releng/10.1
Last change on this file since f416e9b was f416e9b, checked in by Kris Moore <kris@…>, 16 months ago

Change how we set new passwords via the UserManager? GUI, fixes an issue
with the crypt() string only returning 8 chars...

  • Property mode set to 100755
File size: 16.8 KB
Line 
1/***************************************************************************
2 *   Copyright (C) 2005, 2012 by Tim McCormick   *
3 *   tim@pcbsd.org   *
4 *                                                                         *
5 *   Permission is hereby granted, free of charge, to any person obtaining *
6 *   a copy of this software and associated documentation files (the       *
7 *   "Software"), to deal in the Software without restriction, including   *
8 *   without limitation the rights to use, copy, modify, merge, publish,   *
9 *   distribute, sublicense, and/or sell copies of the Software, and to    *
10 *   permit persons to whom the Software is furnished to do so, subject to *
11 *   the following conditions:                                             *
12 *                                                                         *
13 *   The above copyright notice and this permission notice shall be        *
14 *   included in all copies or substantial portions of the Software.       *
15 *                                                                         *
16 *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,       *
17 *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF    *
18 *   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
19 *   IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR     *
20 *   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
21 *   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
22 *   OTHER DEALINGS IN THE SOFTWARE.                                       *
23 ***************************************************************************/
24
25#include "usermanagerback.h"
26#include <qtextstream.h>
27#include <QDebug>
28#include <QUrl>
29#include <QFileInfo>
30#include <QTemporaryFile>
31
32UserManagerBackend::UserManagerBackend(QString dir) {
33    chroot = dir;
34    programInit();
35}
36
37void UserManagerBackend::programInit() {
38    fullnameRegExp.setPattern("([:!@])+");
39    homeLocRegExp.setPattern("^(/usr)?/home/?");
40    usernameRegExp.setPattern("([a-z]*[A-Z]*[0-9]*[_]*)+");
41    passwordRegExp.setPattern("([a-z]*[A-Z]*[0-9]*[!\"£$%^&*()_+=¬#'`@~:?<>|{}\\-.]*)+");
42    groupnameRegExp.setPattern("([a-z]*[A-Z]*[0-9]*[_]*)+");
43}
44
45QStringList UserManagerBackend::getAllUsers(int minId, int maxId) {
46    if (userList.empty()) { refreshUsers(); }
47   
48    qDebug() << "Generating new user list for UI...";
49
50    QStringList result;
51    QMap<QString, User>::Iterator it;
52
53    for ( it = userList.begin(); it != userList.end(); ++it ) {
54        if ((! it->getDeleted()) && (((it->getUid() >= minId) || (minId == -1)) && (it->getUid() <= maxId) || (maxId == -1) || (it->getUid() < 0))) {
55            result.append(it->getUsername());
56        }
57    }
58   
59    qDebug() << "Done Generating new user list for UI...";
60    return result;
61}
62
63void UserManagerBackend::refreshUsers() {
64    qDebug() << "Refreshing user list...";
65    userList.clear();
66    QFile userFile(chroot + "/etc/passwd");
67    if ( userFile.open(QIODevice::ReadOnly) ) {
68        QTextStream stream(&userFile);
69        stream.setCodec("UTF-8");
70        QString line;
71       
72        while ( !stream.atEnd() ) {
73            line = stream.readLine();
74           
75            if ((line.indexOf("#") != 0) && (! line.isEmpty())) { //Make sure it isn't a comment or blank
76                QString username = line.section(":",0,0);
77                int uid = line.section(":",2,2).toInt();
78                int gid = line.section(":",3,3).toInt();
79                QString home = line.section(":",5,5);
80                QString shell = line.section(":",6,6);
81                QString fullname = line.section(":",4,4);
82               
83                userList[username] = User(username, uid, gid, home, shell, fullname);
84            }
85        }
86    }
87    else {
88        //Unable to open file error
89        qWarning("Error! Unable to open /etc/passwd");
90    }
91}
92
93User* UserManagerBackend::getUser(const QString &user) {
94    return &userList.find(user).value();
95}
96
97QStringList UserManagerBackend::getShells() {
98    QStringList result;
99    QFile shellFile(chroot + "/etc/shells");
100    if ( shellFile.open(QIODevice::ReadOnly) ) {
101        QTextStream stream(&shellFile);
102        stream.setCodec("UTF-8");
103
104        QString line;
105       
106        while ( !stream.atEnd() ) {
107            line = stream.readLine();
108           
109            if ((line.indexOf("#") != 0) && (! line.isEmpty())) { //Make sure it isn't a comment or blank
110                result.append(line);
111            }
112        }
113    }
114    else {
115        //Unable to open file error
116        qWarning("Error! Unable to open /etc/shells");
117    }
118   
119    // Add /sbin/nologin as well
120    result.append("/sbin/nologin");
121
122    return result;
123}
124
125QStringList UserManagerBackend::getAllGroups(int minId, int maxId) {
126    if (groupList.empty()) { refreshGroups(); }
127   
128    QStringList result;
129    QMap<int, Group>::Iterator it;
130   
131    qDebug() << "Generating new group list for UI...";
132
133    for ( it = groupList.begin(); it != groupList.end(); ++it ) {
134        if ((! it->getDeleted()) && (((it->getGid() >= minId) || (minId == -1) ) && ((it->getGid() <= maxId) || (maxId == -1 )))) {
135            result.append(it->getGroupname());
136        }
137    }
138
139    qDebug() << "Done Generating new group list for UI...";
140    return result;
141}
142
143void UserManagerBackend::refreshGroups() {
144    qDebug() << "Refreshing group list...";
145    groupList.clear();
146    QFile groupFile(chroot + "/etc/group");
147    if ( groupFile.open(QIODevice::ReadOnly) ) {
148        QTextStream stream(&groupFile);
149        stream.setCodec("UTF-8");
150
151        QString line;
152       
153        while ( !stream.atEnd() ) {
154            line = stream.readLine();
155           
156            if ((line.indexOf("#") != 0) && (! line.isEmpty())) { //Make sure it isn't a comment or blank
157                QString groupname = line.section(":",0,0);
158                int gid = line.section(":",2,2).toInt();
159                QString memberString = line.section(":",3,3);
160                QStringList members = memberString.split(",");
161               
162                groupList[gid] = Group(groupname, gid, members);
163            }
164        }
165    }
166    else {
167        //Unable to open file error
168        qWarning("Error! Unable to open /etc/group");
169    }
170}
171
172Group* UserManagerBackend::getGroup(int gid) {
173    return &groupList.find(gid).value();
174}
175
176Group* UserManagerBackend::getGroup(QString groupname) {
177    Group *result = new Group();
178    QMap<int, Group>::Iterator it;
179   
180    for ( it = groupList.begin(); it != groupList.end(); ++it ) {
181        if (it->getGroupname() == groupname) {
182            result = &it.value();
183        }
184    }
185   
186    return result;
187}
188
189int UserManagerBackend::validatePassword(QString password, QString confirmPassword) {
190    int result = 0;
191    if (password != confirmPassword) {
192        result = 2;
193    }
194    if ((password == "") || (confirmPassword == "")) {
195        result = 1;
196    }
197    if ((! passwordRegExp.exactMatch(password)) && (password != "")) {
198        result = 3;
199    }
200    return result;
201}
202
203void UserManagerBackend::changePassword(QString username, QString password)
204{
205    qDebug() << "running changePassword()";
206    userList[username].setPassword(password);
207    emit usersChanged();
208}
209
210void UserManagerBackend::setEnc(QString username, bool nEnc)
211{
212    userList[username].setEnc(nEnc);
213}
214
215int UserManagerBackend::validateFullname(QString fullname) {
216    int result = 0;
217   
218    if ((fullname.contains(fullnameRegExp) != 0) && (fullname != "")) {
219        result = 2;
220    }
221    if (fullname == "") {
222        result = 1;
223    }
224   
225    return result;
226}
227
228int UserManagerBackend::validateHome(QString home) {
229    int result = 0;
230    QFileInfo homeDir(home);
231    QUrl *homePath = new QUrl(home);
232    if (home == "") {
233        result = 1;
234    }
235    if ((! homeDir.isDir()) && (home != "")) {
236        result = 3;
237    }
238    if ((homeLocRegExp.indexIn(home) == -1) && (home != "")) {
239        result = 4;
240    }   
241    if ((homeDir.isFile()) && (home != "")) {
242        result = 5;
243    }
244    if ((! homePath->isValid()) && (home != "")) {
245        result = 2;
246    }
247   
248    return result;
249}
250
251void UserManagerBackend::deleteUser(QString username)
252{
253    userList[username].setDeleted();
254    emit usersChanged();
255}
256
257int UserManagerBackend::validateUsername(QString username) {
258    //0 = OK, 1 = Empty, 2 = Invalid input, 3 = Username already in use
259    int result = 0;
260   
261    if ((userList.contains(username) == true) && (username != "")) {
262        result = 3;
263    }
264    if ((! usernameRegExp.exactMatch(username)) && (username != "")) {
265        result = 2;
266    }
267    if (username == "") {
268        result = 1;
269    }
270   
271    return result;
272}
273
274void UserManagerBackend::addUser(QString username, QString fullname, QString home, QString shell, QString group, QString password)
275{
276    qDebug() << "Starting addUser " << username;
277    int gid = -1;
278    QMap<int, Group>::Iterator it;
279   
280    for ( it = groupList.begin(); it != groupList.end(); ++it )
281    {
282        if (it->getGroupname() == group)
283        {
284            gid = it->getGid();
285            break;
286        }
287    }
288    userList[username] = User(username, home, shell, fullname, password, gid);
289   
290    emit usersChanged();
291    qDebug() << "Finished addUser: " << username;
292}
293
294void UserManagerBackend::deleteGroup(QString groupname)
295{
296    getGroup(groupname)->setDeleted();
297    emit groupsChanged();
298}
299
300void UserManagerBackend::addGroup(QString groupname)
301{
302    //Find free, invalid id
303    int gid = -1;
304    while (groupList[gid].getStatus() != -1) { gid--; }
305    groupList[gid] = Group(groupname, -1, QStringList(), true);
306    emit groupsChanged();
307}
308
309int UserManagerBackend::validateGroupname(QString groupname) {
310    //0 = OK, 1 = Empty, 2 = Invalid input, 3 = Groupname already in use
311    int result = 0;
312    QMap<int, Group>::Iterator it;
313   
314    for ( it = groupList.begin(); it != groupList.end(); ++it ) {
315        if (it->getGroupname() == groupname) {
316            result = 3;
317        }
318    }
319    if ((! groupnameRegExp.exactMatch(groupname)) && (groupname != "")) {
320        result = 2;
321    }
322    if (groupname == "") {
323        result = 1;
324    }
325   
326    return result;
327}
328
329void UserManagerBackend::addUserToGroup(QString user, QString groupname)
330{
331    Group *group = getGroup(groupname);
332    group->addMember(user);
333    group->setChanges();
334    emit groupsChanged();
335}
336
337void UserManagerBackend::removeUserFromGroup(QString user, QString groupname)
338{
339    Group *group = getGroup(groupname);
340    group->removeMember(user);
341    group->setChanges();
342    emit groupsChanged();
343}
344
345bool UserManagerBackend::commit()
346{
347   
348    //Process users
349    QMap<QString, User>::Iterator userIt;
350
351    QStringList args;
352   
353    for ( userIt = userList.begin(); userIt != userList.end(); ++userIt )
354    {
355        args.clear();
356        switch(userIt->getStatus())
357        {
358            case 1:
359                //Modify User
360                qDebug() << "Modifying user " << userIt->getUsername();
361                if ( ! chroot.isEmpty() )
362                   args << chroot << "pw";
363                args << "usermod";
364                args << userIt->getUsername();
365                // Only change home-dir on non-encrypted users
366                if ( ! userIt->getEnc() ) {
367                  args << "-d";
368                  args << userIt->getHome();
369                }
370                args << "-s";
371                args << userIt->getShell();
372                args << "-c";
373                args << userIt->getFullname();
374                if ( ! chroot.isEmpty() )
375                   QProcess::execute("chroot", args);
376                else
377                   QProcess::execute("pw", args);
378               
379                if (userIt->getPassword() != "")
380                {
381                    // Refuse to continue if we are trying to change PW
382                    // On an encrypted users homedir
383                    if ( userIt->getEnc() ) {
384                      qDebug() << "Cannot change encrypted password: " << userIt->getUsername();
385                      break;
386                    }
387                    qDebug() << "Changing password: " << userIt->getUsername();
388
389                    // Set the new PW
390                    QTemporaryFile rfile("/tmp/.XXXXXXXX");
391                    if ( rfile.open() ) {
392                      QTextStream stream( &rfile );
393                      stream << userIt->getClearPassword();
394                      rfile.close();
395                    }
396                    if ( ! chroot.isEmpty() )
397                      system("cat " + rfile.fileName().toLatin1() + " | chroot " + chroot.toLatin1() + " pw usermod " + userIt->getUsername().toLatin1() + " -h 0 ");
398                    else
399                      system("cat " + rfile.fileName().toLatin1() + " | pw usermod " + userIt->getUsername().toLatin1() + " -h 0 ");
400
401                    rfile.remove();
402                }
403                break;
404            case 2:
405            {
406                //Add User
407                qDebug() << "Adding user " << userIt->getUsername();
408                // Create the new home-directory
409                if ( chroot.isEmpty() ) {
410                   system("/usr/local/share/pcbsd/scripts/mkzfsdir.sh " + userIt->getHome().toLatin1() );
411                   system("pw groupadd " + userIt->getUsername().toLatin1() );
412                } else {
413                   system("mkdir -p " + chroot.toLatin1() + "/" + userIt->getHome().toLatin1() + " 2>/dev/null" );
414                   system("chroot " + chroot.toLatin1() + " ln -s /usr/home /home 2>/dev/null" );
415                   system("chroot " + chroot.toLatin1() + " pw groupadd " + userIt->getUsername().toLatin1() );
416                }
417
418                if ( ! chroot.isEmpty() )
419                   args << chroot << "pw";
420                args << "useradd";
421                args << userIt->getUsername();
422                args << "-c";
423                args << userIt->getFullname();
424                args << "-m";
425                args << "-d";
426                args << userIt->getHome();
427                args << "-s";
428                args << userIt->getShell();
429                if (userIt->getGid() != -1)
430                {
431                    args << "-g";
432                    args << QString::number(userIt->getGid());
433                } else {
434                    args << "-g";
435                    args << userIt->getUsername();
436                }
437                args << "-G";
438                args << "operator";
439                if ( ! chroot.isEmpty() )
440                   QProcess::execute("chroot", args);
441                else
442                   QProcess::execute("pw", args);
443
444                QTemporaryFile nfile("/tmp/.XXXXXXXX");
445                if ( nfile.open() ) {
446                  QTextStream stream( &nfile );
447                  stream << userIt->getClearPassword();
448                  nfile.close();
449                }
450                if ( ! chroot.isEmpty() )
451                  system("cat " + nfile.fileName().toLatin1() + " | chroot " + chroot.toLatin1() + " pw usermod " + userIt->getUsername().toLatin1() + " -h 0 ");
452                else
453                  system("cat " + nfile.fileName().toLatin1() + " | pw usermod " + userIt->getUsername().toLatin1() + " -h 0 ");
454                nfile.remove();
455
456                if ( chroot.isEmpty() ) {
457                   qDebug() << "Enabling Flash Plugin for " << userIt->getUsername();
458                   QString flashCmd = "su -m " + userIt->getUsername() + " -c \"flashpluginctl on\"";
459                   system(flashCmd.toLatin1());
460                }
461
462                // Set permissions
463                if ( chroot.isEmpty() )
464                   system("chown -R " + userIt->getUsername().toLatin1() +":" + userIt->getUsername().toLatin1() + " "  + userIt->getHome().toLatin1() );
465                else
466                   system("chroot " + chroot.toLatin1() + " chown -R " + userIt->getUsername().toLatin1() +":" + userIt->getUsername().toLatin1() + " "  + userIt->getHome().toLatin1() );
467
468                // Are we enabling encryption?
469                if ( userIt->getEnc() ) {
470                   system("enable_user_pefs " + userIt->getUsername().toLatin1() + " " + userIt->getClearPassword().toLatin1() );
471                }
472
473                break;
474            }
475            case 3:
476                //Delete User
477                qDebug() << "Deleting user " << userIt->getUsername();
478
479                if(userIt->getEnc()) {
480                  // Unmount PEFS
481                  system("umount " + userIt->getHome().toLatin1() );
482                }
483                if ( ! chroot.isEmpty() )
484                   args << chroot << "pw";
485                args << "userdel";
486                args << userIt->getUsername();
487                if(userIt->getDeleteHome()) {
488                        args << "-r";
489                        system("/usr/local/share/pcbsd/scripts/rmzfsdir.sh " + userIt->getHome().toLatin1() );
490                }
491                if ( ! chroot.isEmpty() )
492                   QProcess::execute("chroot", args);
493                else
494                   QProcess::execute("pw", args);
495                break;
496        }
497    }
498    refreshUsers();
499   
500    //Process groups
501    QMap<int, Group>::Iterator groupIt;
502 
503    for ( groupIt = groupList.begin(); groupIt != groupList.end(); ++groupIt )
504    {
505        args.clear();
506        switch(groupIt->getStatus())
507        {
508            case 1:
509                //Modify Group
510                qDebug() << "Modifying group " << groupIt->getGroupname();
511                if ( ! chroot.isEmpty() )
512                   args << chroot << "pw";
513                args << "groupmod";
514                args << groupIt->getGroupname();
515                args << "-M";
516                args << groupIt->getMembers().join(",");
517                if ( ! chroot.isEmpty() )
518                   QProcess::execute("chroot", args);
519                else
520                   QProcess::execute("pw", args);
521                break;
522            case 2:
523                //Add Group
524                qDebug() << "Adding group " << groupIt->getGroupname();
525                if ( ! chroot.isEmpty() )
526                   args << chroot << "pw";
527                args << "groupadd";
528                args << groupIt->getGroupname();
529                args << "-M";
530                args << groupIt->getMembers().join(",");
531                if ( ! chroot.isEmpty() )
532                   QProcess::execute("chroot", args);
533                else
534                   QProcess::execute("pw", args);
535                break;
536            case 3:
537                //Delete Group
538                qDebug() << "Deleting group " << groupIt->getGroupname();
539                if ( ! chroot.isEmpty() )
540                   args << chroot << "pw";
541                args << "groupdel";
542                args << groupIt->getGroupname();
543                if ( ! chroot.isEmpty() )
544                   QProcess::execute("chroot", args);
545                else
546                   QProcess::execute("pw", args);
547                break;
548        }
549    }
550    refreshGroups();
551    emit groupsChanged();
552    emit usersChanged();
553   
554    return true;
555}
556
Note: See TracBrowser for help on using the repository browser.