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

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

Add ability to PEFS encrypt users home-directories when we
create a new user via the user-manager GUI

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