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

9.2-releasereleng/10.0releng/10.0.1
Last change on this file since 83428f0 was 83428f0, checked in by Kris Moore <kris@…>, 8 months ago

Make sure to pass args to enable_user_pefs using a QProcess, in order to get any special
chars properly

  • 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                   QProcess::execute("enable_user_pefs", QStringList() << userIt->getUsername() << userIt->getClearPassword() );
471
472                }
473
474                break;
475            }
476            case 3:
477                //Delete User
478                qDebug() << "Deleting user " << userIt->getUsername();
479
480                if(userIt->getEnc()) {
481                  // Unmount PEFS
482                  system("umount " + userIt->getHome().toLatin1() );
483                }
484                if ( ! chroot.isEmpty() )
485                   args << chroot << "pw";
486                args << "userdel";
487                args << userIt->getUsername();
488                if(userIt->getDeleteHome()) {
489                        args << "-r";
490                        system("/usr/local/share/pcbsd/scripts/rmzfsdir.sh " + userIt->getHome().toLatin1() );
491                }
492                if ( ! chroot.isEmpty() )
493                   QProcess::execute("chroot", args);
494                else
495                   QProcess::execute("pw", args);
496                break;
497        }
498    }
499    refreshUsers();
500   
501    //Process groups
502    QMap<int, Group>::Iterator groupIt;
503 
504    for ( groupIt = groupList.begin(); groupIt != groupList.end(); ++groupIt )
505    {
506        args.clear();
507        switch(groupIt->getStatus())
508        {
509            case 1:
510                //Modify Group
511                qDebug() << "Modifying group " << groupIt->getGroupname();
512                if ( ! chroot.isEmpty() )
513                   args << chroot << "pw";
514                args << "groupmod";
515                args << groupIt->getGroupname();
516                args << "-M";
517                args << groupIt->getMembers().join(",");
518                if ( ! chroot.isEmpty() )
519                   QProcess::execute("chroot", args);
520                else
521                   QProcess::execute("pw", args);
522                break;
523            case 2:
524                //Add Group
525                qDebug() << "Adding group " << groupIt->getGroupname();
526                if ( ! chroot.isEmpty() )
527                   args << chroot << "pw";
528                args << "groupadd";
529                args << groupIt->getGroupname();
530                args << "-M";
531                args << groupIt->getMembers().join(",");
532                if ( ! chroot.isEmpty() )
533                   QProcess::execute("chroot", args);
534                else
535                   QProcess::execute("pw", args);
536                break;
537            case 3:
538                //Delete Group
539                qDebug() << "Deleting group " << groupIt->getGroupname();
540                if ( ! chroot.isEmpty() )
541                   args << chroot << "pw";
542                args << "groupdel";
543                args << groupIt->getGroupname();
544                if ( ! chroot.isEmpty() )
545                   QProcess::execute("chroot", args);
546                else
547                   QProcess::execute("pw", args);
548                break;
549        }
550    }
551    refreshGroups();
552    emit groupsChanged();
553    emit usersChanged();
554   
555    return true;
556}
557
Note: See TracBrowser for help on using the repository browser.