mirror of
https://github.com/outbackdingo/sysadm.git
synced 2026-01-27 10:20:26 +00:00
Merge pull request #4 from ldemouy/master
Create a UserManager for sysadm
This commit is contained in:
@@ -14,17 +14,19 @@ HEADERS += sysadm-global.h \
|
||||
sysadm-general.h \
|
||||
sysadm-lifepreserver.h \
|
||||
sysadm-network.h \
|
||||
sysadm-firewall.h
|
||||
sysadm-firewall.h \
|
||||
sysadm-usermanager.h
|
||||
|
||||
SOURCES += sysadm-general.cpp \
|
||||
sysadm-lifepreserver.cpp \
|
||||
sysadm-network.cpp \
|
||||
NetDevice.cpp \
|
||||
sysadm-firewall.cpp
|
||||
sysadm-firewall.cpp \
|
||||
sysadm-usermanager.cpp
|
||||
|
||||
include.path=/usr/local/include/
|
||||
include.files=sysadm-*.h
|
||||
|
||||
INSTALLS += target include
|
||||
INSTALLS += target include
|
||||
|
||||
QMAKE_LIBDIR = /usr/local/lib/qt5 /usr/local/lib
|
||||
|
||||
365
src/library/sysadm-usermanager.cpp
Normal file
365
src/library/sysadm-usermanager.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
//===========================================
|
||||
// PC-BSD source code
|
||||
// Copyright (c) 2015, PC-BSD Software/iXsystems
|
||||
// Available under the 3-clause BSD license
|
||||
// See the LICENSE file for full details
|
||||
//===========================================
|
||||
#include "sysadm-usermanager.h"
|
||||
#include "sysadm-general.h"
|
||||
using namespace sysadm;
|
||||
|
||||
UserManager::UserManager(QString chroot)
|
||||
{
|
||||
this->chroot = chroot;
|
||||
loadUsers();
|
||||
loadGroups();
|
||||
loadShells();
|
||||
}
|
||||
|
||||
void UserManager::NewUser(QString fullName, QString userName, QString password, QString shell)
|
||||
{
|
||||
User user;
|
||||
user.UserName = userName;
|
||||
user.FullName = fullName;
|
||||
user.HomeFolder = "/usr/home/"+userName;
|
||||
user.Shell = shell;
|
||||
|
||||
//Add User
|
||||
qDebug() << "Adding user " << userName;
|
||||
// Create the zfs dataset associated with the home directory
|
||||
if ( chroot.isEmpty() )
|
||||
{
|
||||
QStringList args;
|
||||
args.append(user.HomeFolder);
|
||||
General::RunCommand("/usr/local/share/pcbsd/scripts/mkzfsdir.sh",args);
|
||||
}
|
||||
|
||||
QStringList args;
|
||||
if ( ! chroot.isEmpty() ) //if chroot is not empty the command starts with chroot instead of pw
|
||||
args << chroot << "pw"; //and thus we have to add it as an argument
|
||||
args << "useradd"; //create a user
|
||||
args << userName; //with this userName
|
||||
args << "-c"; //sets the comment field
|
||||
args << "\""+ fullName+"\""; //with the full name of the user
|
||||
args << "-m"; //create the user's home directory
|
||||
args << "-s"; //set the user's shell
|
||||
args << shell; //to this
|
||||
args << "-G"; //additionally add the user to
|
||||
args << "operator"; //the operator's group
|
||||
|
||||
if ( ! chroot.isEmpty() ) //if we're operating with a chroot call
|
||||
General::RunCommand("chroot", args);
|
||||
else //otherwise
|
||||
General::RunCommand("pw", args);
|
||||
|
||||
ChangeUserPassword(user,password);
|
||||
|
||||
//enable flash for the user
|
||||
if ( chroot.isEmpty() ) { //if we're not in a chroot
|
||||
qDebug() << "Enabling Flash Plugin for " << userName;
|
||||
args.clear();
|
||||
args << userName; //run command as this user
|
||||
args << "-c"; //with the command
|
||||
args << "\"flashpluginctl on\""; //turn on flashpluginctl
|
||||
General::RunCommand("su",args);
|
||||
}
|
||||
|
||||
//reloads the groups and users so that the internal model is consistent
|
||||
loadUsers();
|
||||
loadGroups();
|
||||
}
|
||||
|
||||
void UserManager::DeleteUser(User user)
|
||||
{
|
||||
//Delete User
|
||||
qDebug() << "Deleting user " << user.UserName;
|
||||
|
||||
//remove the dataset associated with the home folder
|
||||
QStringList args;
|
||||
args << user.HomeFolder;
|
||||
General::RunCommand("/usr/local/share/pcbsd/scripts/rmzfsdir.sh",args);
|
||||
|
||||
//delete the user and their home directory
|
||||
args.clear();
|
||||
if ( ! chroot.isEmpty() ) //if we're in a chroot we need to use chroot before pw
|
||||
args << chroot << "pw";
|
||||
args << "userdel"; //delete a user
|
||||
args << user.UserName; //this user
|
||||
args << "-r"; //remove the contents of the user's home directory
|
||||
if ( ! chroot.isEmpty() )
|
||||
General::RunCommand("chroot", args);
|
||||
else
|
||||
General::RunCommand("pw", args);
|
||||
|
||||
loadUsers();
|
||||
loadGroups();
|
||||
}
|
||||
|
||||
const QVector<User> UserManager::GetUsers()
|
||||
{
|
||||
return users;
|
||||
}
|
||||
|
||||
const User UserManager::GetUser(int id)
|
||||
{
|
||||
for(User user: users)
|
||||
{
|
||||
if(user.ID == id)
|
||||
return user;
|
||||
}
|
||||
return User();
|
||||
}
|
||||
|
||||
const User UserManager::GetUser(QString userName)
|
||||
{
|
||||
for(User user: users)
|
||||
{
|
||||
if(user.UserName == userName)
|
||||
return user;
|
||||
}
|
||||
return User();
|
||||
}
|
||||
|
||||
void UserManager::ChangeUserPassword(User user, QString newPassword)
|
||||
{
|
||||
|
||||
//Create a temporary file to store the password in
|
||||
QTemporaryFile nfile("/tmp/.XXXXXXXX");
|
||||
if ( nfile.open() )
|
||||
{
|
||||
QTextStream stream( &nfile );
|
||||
stream << newPassword;
|
||||
nfile.close();
|
||||
}
|
||||
|
||||
//set the user password
|
||||
QStringList args;
|
||||
args.append(nfile.fileName()); //the temp file holding the password
|
||||
args.append("|"); //which we're going to pipe to the stdin of
|
||||
if ( ! chroot.isEmpty() ) //if we're in a chroot
|
||||
{
|
||||
args << "chroot"; //a chroot
|
||||
args << chroot; //located here
|
||||
}
|
||||
args << "pw"; //change users
|
||||
args << "usermod"; //where we're going to modify a user
|
||||
args << user.UserName;//this user
|
||||
args << "-h"; //set the user's password
|
||||
args << "0"; //using stdin
|
||||
General::RunCommand("cat",args);
|
||||
|
||||
//remove the temp file holding the password
|
||||
nfile.remove();
|
||||
|
||||
}
|
||||
|
||||
void UserManager::ChangeUserShell(User user, QString shell)
|
||||
{
|
||||
if(shells.contains(shell))
|
||||
{
|
||||
qDebug("Shell found");
|
||||
QStringList args;
|
||||
args << "usermod"; // modify the user
|
||||
args << "-n"; //specify a user name
|
||||
args << user.UserName; //for this user
|
||||
args << "-s"; //set the shell to
|
||||
args << shell; //this shell
|
||||
General::RunCommand("pw",args);
|
||||
}
|
||||
else
|
||||
qDebug("Shell not found");
|
||||
|
||||
loadUsers();
|
||||
}
|
||||
|
||||
void UserManager::ChangeUserFullName(User user, QString newName)
|
||||
{
|
||||
QStringList args;
|
||||
args << "usermod"; //modify the user
|
||||
args << user.UserName; //for this user
|
||||
args << "-c"; //change the gecos field to
|
||||
args << newName; //this name
|
||||
General::RunCommand("pw",args);
|
||||
loadUsers();
|
||||
}
|
||||
|
||||
void UserManager::AddUserToGroup(User user, Group group)
|
||||
{
|
||||
QStringList args;
|
||||
args << "groupmod"; //modify a group
|
||||
args << "-n"; //modify for a group
|
||||
args << group.Name;//this group
|
||||
args << "-m";//by adding a member
|
||||
args << user.UserName; //this user
|
||||
General::RunCommand("pw",args);
|
||||
|
||||
loadGroups();
|
||||
}
|
||||
|
||||
void UserManager::RemoveUserFromGroup(User user, Group group)
|
||||
{
|
||||
QStringList args;
|
||||
args << "groupmod"; //modify a group
|
||||
args << "-n"; //modify for a group
|
||||
args << group.Name; //this group
|
||||
args << "-d"; //by removing a user
|
||||
args << user.UserName ; //this user
|
||||
General::RunCommand("pw", args);
|
||||
|
||||
loadGroups();
|
||||
}
|
||||
|
||||
void UserManager::NewGroup(QString name, QStringList members)
|
||||
{
|
||||
QStringList args;
|
||||
qDebug() << "Adding group " << name;
|
||||
if ( ! chroot.isEmpty() ) //if we're in a chroot need to add chroot before pw
|
||||
args << chroot << "pw";
|
||||
args << "groupadd"; //create a new group
|
||||
args << name; // with this name
|
||||
args << "-M"; //with this list of users
|
||||
args << members.join(","); //these guys
|
||||
if ( ! chroot.isEmpty() ) //if we're in a chroot
|
||||
General::RunCommand("chroot", args);
|
||||
else
|
||||
General::RunCommand("pw", args);
|
||||
|
||||
loadGroups();
|
||||
}
|
||||
|
||||
void UserManager::DeleteGroup(Group group)
|
||||
{
|
||||
QStringList args;
|
||||
qDebug() << "Deleting group " << group.Name;
|
||||
if ( ! chroot.isEmpty() ) //if we're in a chroot need to add chroot before pw
|
||||
args << chroot << "pw";
|
||||
args << "groupdel"; //delete a group
|
||||
args << group.Name; //of this name
|
||||
if ( ! chroot.isEmpty() ) //if we're in a chroot
|
||||
General::RunCommand("chroot", args);
|
||||
else
|
||||
General::RunCommand("pw", args);
|
||||
|
||||
loadGroups();
|
||||
}
|
||||
|
||||
const QVector<Group> UserManager::GetGroups()
|
||||
{
|
||||
return groups;
|
||||
}
|
||||
|
||||
const Group UserManager::getGroup(int id)
|
||||
{
|
||||
for(Group group : groups)
|
||||
{
|
||||
if(group.ID == id)
|
||||
return group;
|
||||
}
|
||||
return Group();
|
||||
}
|
||||
|
||||
const Group UserManager::getGroup(QString name)
|
||||
{
|
||||
for(Group group : groups)
|
||||
{
|
||||
if(group.Name == name)
|
||||
return group;
|
||||
}
|
||||
return Group();
|
||||
}
|
||||
|
||||
const QStringList UserManager::GetShells()
|
||||
{
|
||||
return shells;
|
||||
}
|
||||
|
||||
void UserManager::loadUsers()
|
||||
{
|
||||
users.clear();
|
||||
QFile userFile(chroot + "/etc/passwd");
|
||||
if ( userFile.open(QIODevice::ReadOnly) )
|
||||
{
|
||||
QTextStream stream(&userFile);
|
||||
stream.setCodec("UTF-8");
|
||||
QString line;
|
||||
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
line = stream.readLine();
|
||||
|
||||
if ((line.indexOf("#") != 0) && (! line.isEmpty())) //Make sure it isn't a comment or blank
|
||||
{
|
||||
User user;
|
||||
user.UserName = line.section(":",0,0);
|
||||
user.ID = line.section(":",2,2).toInt();
|
||||
user.GroupID = line.section(":",3,3).toInt();
|
||||
user.HomeFolder = line.section(":",5,5);
|
||||
user.Shell = line.section(":",6,6);
|
||||
user.FullName = line.section(":",4,4);
|
||||
|
||||
users.append(user);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Unable to open file error
|
||||
qWarning("Error! Unable to open /etc/passwd");
|
||||
}
|
||||
}
|
||||
|
||||
void UserManager::loadGroups()
|
||||
{
|
||||
groups.clear();
|
||||
QFile groupFile(chroot + "/etc/group");
|
||||
if ( groupFile.open(QIODevice::ReadOnly) )
|
||||
{
|
||||
QTextStream stream(&groupFile);
|
||||
stream.setCodec("UTF-8");
|
||||
|
||||
QString line;
|
||||
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
line = stream.readLine();
|
||||
|
||||
if ((line.indexOf("#") != 0) && (! line.isEmpty())) //Make sure it isn't a comment or blank
|
||||
{
|
||||
Group group;
|
||||
group.Name = line.section(":",0,0);
|
||||
group.ID = line.section(":",2,2).toInt();
|
||||
QString memberString = line.section(":",3,3);
|
||||
group.Members = memberString.split(",");
|
||||
|
||||
groups.append(group);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Unable to open file error
|
||||
qWarning("Error! Unable to open /etc/group");
|
||||
}
|
||||
}
|
||||
|
||||
void UserManager::loadShells()
|
||||
{
|
||||
shells.clear();
|
||||
QFile shellFile(chroot + "/etc/shells");
|
||||
if ( shellFile.open(QIODevice::ReadOnly) ) {
|
||||
QTextStream stream(&shellFile);
|
||||
stream.setCodec("UTF-8");
|
||||
|
||||
QString line;
|
||||
|
||||
while ( !stream.atEnd() ) {
|
||||
line = stream.readLine();
|
||||
|
||||
if ( !line.startsWith("#") && !line.isEmpty() ) { //Make sure it isn't a comment or blank
|
||||
shells.append(line);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Unable to open file error
|
||||
qWarning("Error! Unable to open /etc/shells");
|
||||
}
|
||||
|
||||
// Add /sbin/nologin as well
|
||||
shells.append("/sbin/nologin");
|
||||
}
|
||||
194
src/library/sysadm-usermanager.h
Normal file
194
src/library/sysadm-usermanager.h
Normal file
@@ -0,0 +1,194 @@
|
||||
//===========================================
|
||||
// PC-BSD source code
|
||||
// Copyright (c) 2015, PC-BSD Software/iXsystems
|
||||
// Available under the 3-clause BSD license
|
||||
// See the LICENSE file for full details
|
||||
//===========================================
|
||||
|
||||
#ifndef USERMANAGER_H
|
||||
#define USERMANAGER_H
|
||||
#include<QtCore>
|
||||
|
||||
namespace sysadm{
|
||||
class User
|
||||
{
|
||||
public:
|
||||
User()
|
||||
{
|
||||
FullName = "";
|
||||
UserName = "";
|
||||
ID = -1;
|
||||
HomeFolder = "";
|
||||
Shell = "";
|
||||
GroupID = -1;
|
||||
}
|
||||
|
||||
QString FullName;
|
||||
QString UserName;
|
||||
int ID;
|
||||
QString HomeFolder;
|
||||
QString Shell;
|
||||
int GroupID;
|
||||
friend bool operator<(const User lhs, const User rhs){
|
||||
return std::tie(lhs.ID,lhs.UserName) < std::tie(rhs.ID,rhs.UserName);
|
||||
}
|
||||
friend bool operator>(const User lhs, const User rhs)
|
||||
{ return rhs < lhs;}
|
||||
friend bool operator==(const User lhs, const User rhs)
|
||||
{
|
||||
return lhs.ID == rhs.ID && lhs.UserName == rhs.UserName;
|
||||
}
|
||||
friend bool operator !=(const User lhs, const User rhs)
|
||||
{ return !(lhs == rhs);}
|
||||
};
|
||||
class Group
|
||||
{
|
||||
public:
|
||||
Group()
|
||||
{
|
||||
ID = -1;
|
||||
Name = "";
|
||||
Members = QStringList();
|
||||
}
|
||||
|
||||
int ID;
|
||||
QString Name;
|
||||
//While the object model would be more "correct" if
|
||||
//Users were to be a Vector of User pointers, it's
|
||||
//expensive to wire up and we don't really gain anything
|
||||
//from doing so
|
||||
QStringList Members;
|
||||
};
|
||||
|
||||
class UserManager
|
||||
{
|
||||
public:
|
||||
UserManager(QString chroot = "");
|
||||
|
||||
//#section user actions
|
||||
/**
|
||||
* @brief NewUser Create a new user
|
||||
* @param fullName The full name of the user
|
||||
* @param userName The username of the user
|
||||
* @param password The user's password
|
||||
* @param shell the user's shell, defaults to /bin/tcsh
|
||||
*/
|
||||
void NewUser(QString fullName, QString userName, QString password, QString shell = "/bin/tcsh");
|
||||
/**
|
||||
* @brief DeleteUser Deletes a user
|
||||
* @param user the user to delete
|
||||
*/
|
||||
void DeleteUser(User user);
|
||||
|
||||
/**
|
||||
* @brief GetUsers getter for the users vector
|
||||
* @return a QVector<Users> that is a copy of the current state
|
||||
* do not modify it, instead call functions on this class to change
|
||||
* things and then get another copy of the vector
|
||||
*/
|
||||
const QVector<User> GetUsers();
|
||||
/**
|
||||
* @brief GetUser get a particular user by their UID
|
||||
* @param id the UID of the user to get
|
||||
* @return the user with the UID specified, if not found
|
||||
* returns a blank User
|
||||
*/
|
||||
const User GetUser(int id);
|
||||
|
||||
/**
|
||||
* @brief GetUser get a particular user by their UID
|
||||
* @param userName the username of the user to get
|
||||
* @return the user with the user name specified, if not found
|
||||
* returns a blank User
|
||||
*/
|
||||
const User GetUser(QString userName);
|
||||
|
||||
/**
|
||||
* @brief ChangeUserPassword changes the specified user's password
|
||||
* @param user the user to change the password of
|
||||
* @param newPassword the new password
|
||||
*/
|
||||
void ChangeUserPassword(User user, QString newPassword);
|
||||
/**
|
||||
* @brief ChangeUserShell change a specified user's shell
|
||||
* @param user the user to change the shell for
|
||||
* @param shell the shell to change to, note that if the shell
|
||||
* is not in the shells list then it does nothing
|
||||
*/
|
||||
void ChangeUserShell(User user, QString shell);
|
||||
/**
|
||||
* @brief ChangeUserFullName change the gecos field of a user to a new name
|
||||
* @param user the user to change the name of
|
||||
* @param newName the name to change to
|
||||
*/
|
||||
void ChangeUserFullName(User user, QString newName);
|
||||
//#endsection
|
||||
|
||||
//#section group actions
|
||||
/**
|
||||
* @brief AddUserToGroup add the specified user to the specified group
|
||||
* @param user the user to add to the group
|
||||
* @param group the group to add the user to
|
||||
*/
|
||||
void AddUserToGroup(User user, Group group);
|
||||
/**
|
||||
* @brief RemoveUserFromGroup removes the specified user from the specified group
|
||||
* @param user the user to remove from the group
|
||||
* @param group the group to remove the user from
|
||||
*/
|
||||
void RemoveUserFromGroup(User user, Group group);
|
||||
|
||||
/**
|
||||
* @brief NewGroup creates a new group
|
||||
* @param name the name of the new group
|
||||
* @param Users a list of users to add to the group
|
||||
*/
|
||||
void NewGroup(QString name, QStringList Users = QStringList());
|
||||
/**
|
||||
* @brief DeleteGroup delete a specified group
|
||||
* @param group the group to delete
|
||||
*/
|
||||
void DeleteGroup(Group group);
|
||||
|
||||
/**
|
||||
* @brief GetGroups get the internal list of groups
|
||||
* @return a QVector<Group> that is a copy of the current state
|
||||
* do not modify it, instead call functions on this class to change
|
||||
* things and then get another copy of the vector
|
||||
*/
|
||||
const QVector<Group> GetGroups();
|
||||
/**
|
||||
* @brief getGroup get a specified group by their gid
|
||||
* @param id the gid of the group to get
|
||||
* @return the group with the specified gid
|
||||
*/
|
||||
const Group getGroup(int id);
|
||||
/**
|
||||
* @brief getGroup get a specified group by their name
|
||||
* @param name the name of the group to get
|
||||
* @return the group with the specified name
|
||||
*/
|
||||
const Group getGroup(QString name);
|
||||
//#endsection
|
||||
|
||||
/**
|
||||
* @brief GetShells the list of shells that are currently installed on the system
|
||||
* @return a QStringList of shells on the system
|
||||
*/
|
||||
const QStringList GetShells();
|
||||
|
||||
private:
|
||||
QVector<User> users;
|
||||
QVector<Group> groups;
|
||||
QStringList shells;
|
||||
QString chroot;
|
||||
|
||||
//loads the users from /etc/passwd
|
||||
void loadUsers();
|
||||
//load the groups from /etc/group
|
||||
void loadGroups();
|
||||
//load the shells from /etc/shells
|
||||
void loadShells();
|
||||
};
|
||||
}
|
||||
#endif // USERMANAGER_H
|
||||
Reference in New Issue
Block a user