mirror of
https://github.com/outbackdingo/sysadm.git
synced 2026-01-27 10:20:26 +00:00
Remove the old library directory from the sysadm source tree
This commit is contained in:
@@ -1,325 +0,0 @@
|
||||
//===========================================
|
||||
// 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
|
||||
//===========================================
|
||||
// Note: This was almost entirely written by Tim McCormick in 2009 for
|
||||
// the first PC-BSD library, and copied here by Ken Moore in 2015
|
||||
//===========================================
|
||||
#include "sysadm-network.h"
|
||||
#include "sysadm-general.h"
|
||||
|
||||
#include "sysadm-global.h"
|
||||
|
||||
using namespace sysadm;
|
||||
|
||||
//====================
|
||||
// STATIC LISTING FUNCTION
|
||||
//====================
|
||||
QStringList NetDevice::listNetDevices(){
|
||||
QStringList result;
|
||||
struct ifaddrs *ifap;
|
||||
getifaddrs(&ifap);
|
||||
char ifName[IFNAMSIZ];
|
||||
//Probe the system for each device (one at a time)
|
||||
while (ifap != NULL){
|
||||
strncpy(ifName, ifap->ifa_name, IFNAMSIZ);
|
||||
if (result.contains(ifName) == 0) result += ifName;
|
||||
ifap = ifap->ifa_next;
|
||||
}
|
||||
//Close the
|
||||
freeifaddrs(ifap);
|
||||
return result;
|
||||
}
|
||||
|
||||
//=====================
|
||||
// CLASS FUNCTIONS
|
||||
//=====================
|
||||
//Get the name of the device (taking off any numbers)
|
||||
QString NetDevice::devName(){
|
||||
uint pos = name.indexOf(QRegExp("[0-9]+$"));
|
||||
QString result = name;
|
||||
result.truncate(pos);
|
||||
return result;
|
||||
}
|
||||
|
||||
//Return just the number of the device (removing the name)
|
||||
uint NetDevice::devNum(){
|
||||
uint pos = name.indexOf(QRegExp("[0-9]+$"));
|
||||
return name.mid(pos).toInt();
|
||||
}
|
||||
|
||||
//Fetch the IP and return it as a QString
|
||||
QString NetDevice::ipAsString(){
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
|
||||
strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
|
||||
int s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
ioctl(s, SIOCGIFADDR, &ifr);
|
||||
struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
|
||||
return QString(inet_ntoa(in));
|
||||
}
|
||||
|
||||
//Fetch the IPv6 and return it as a QString
|
||||
QString NetDevice::ipv6AsString(){
|
||||
//Get the sockaddr for the device
|
||||
struct sockaddr *sadd = 0;
|
||||
struct ifaddrs *addrs;
|
||||
if( 0!=getifaddrs( &addrs ) ){ qDebug() << "Could not get addrs"; return ""; }
|
||||
while(sadd==0 && addrs!=0){
|
||||
if( QString(addrs->ifa_name)==name && addrs->ifa_addr->sa_family==AF_INET6){
|
||||
//Found device (with IPv6 address)
|
||||
sadd = addrs->ifa_addr;
|
||||
break;
|
||||
}else{
|
||||
//Move to the next device
|
||||
addrs = addrs->ifa_next;
|
||||
}
|
||||
}
|
||||
free(addrs);
|
||||
if(sadd==0){ qDebug() << "No socket address found"; return ""; }
|
||||
//Now get the IPv6 address in string form
|
||||
char straddr[INET6_ADDRSTRLEN];
|
||||
int err = getnameinfo(sadd, sadd->sa_len, straddr, sizeof(straddr),NULL, 0, NI_NUMERICHOST);
|
||||
if(err!=0){
|
||||
qDebug() << "getnameinfo error:" << gai_strerror(err);
|
||||
return "";
|
||||
}else{
|
||||
return QString(straddr);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//Fetch the netmask and return it as a QString
|
||||
QString NetDevice::netmaskAsString(){
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
|
||||
strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
|
||||
int s = socket(PF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
ioctl(s, SIOCGIFNETMASK, &ifr);
|
||||
struct in_addr in = ((sockaddr_in *) &ifr.ifr_addr)->sin_addr;
|
||||
|
||||
return QString(inet_ntoa(in));
|
||||
}
|
||||
|
||||
//Returns the description string for the device
|
||||
QString NetDevice::desc(){
|
||||
return General::sysctl("dev." + devName() + "." + QString::number(devNum()) + ".%desc");
|
||||
}
|
||||
|
||||
//Fetch the mac address as a QString
|
||||
QString NetDevice::macAsString(){
|
||||
int mib[6];
|
||||
size_t len;
|
||||
char *buf;
|
||||
struct sockaddr_dl *sdl;
|
||||
char *ptr;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = AF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_LINK;
|
||||
mib[4] = NET_RT_IFLIST;
|
||||
mib[5] = if_nametoindex(name.toLocal8Bit());
|
||||
|
||||
//First find the size of the return, so we can adjust buf accordingly
|
||||
sysctl(mib, 6, NULL, &len, NULL, 0);
|
||||
buf = (char *) malloc(len);
|
||||
sysctl(mib, 6, buf, &len, NULL, 0);
|
||||
|
||||
sdl = (sockaddr_dl *)(((if_msghdr *)buf)+1);
|
||||
ptr = (char *) LLADDR(sdl);
|
||||
|
||||
QString mac;
|
||||
for (uint i=0; i < 6; i++){
|
||||
mac += QString::number(*(ptr+i), 16).right(2).rightJustified(2, '0');
|
||||
if(i<5){ mac += ":"; }
|
||||
}
|
||||
return mac;
|
||||
}
|
||||
|
||||
//Get the status of the device (active, associated, etc...)
|
||||
QString NetDevice::mediaStatusAsString(){
|
||||
struct ifmediareq ifm;
|
||||
memset(&ifm, 0, sizeof(struct ifmediareq));
|
||||
|
||||
strncpy(ifm.ifm_name, name.toLocal8Bit(), IFNAMSIZ);
|
||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
ioctl(s, SIOCGIFMEDIA, &ifm);
|
||||
QString status;
|
||||
|
||||
switch (IFM_TYPE(ifm.ifm_active)){
|
||||
case IFM_FDDI:
|
||||
case IFM_TOKEN:
|
||||
if (ifm.ifm_status & IFM_ACTIVE) status = "inserted";
|
||||
else status = "no ring";
|
||||
break;
|
||||
case IFM_IEEE80211:
|
||||
if (ifm.ifm_status & IFM_ACTIVE) status = "associated";
|
||||
else status = "no carrier";
|
||||
break;
|
||||
default:
|
||||
if (ifm.ifm_status & IFM_ACTIVE) status = "active";
|
||||
else status = "no carrier";
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
QString NetDevice::gatewayAsString(){
|
||||
QString info = General::RunCommand("nice netstat -n -r").split("\n").filter(name).filter("default").join("\n");
|
||||
if(info.isEmpty()){ return ""; }
|
||||
//Pull the gateway out of the first line (<default> <gateway>)
|
||||
info = info.replace("\t"," ").section("\n",0,0).simplified(); //ensure proper parsing
|
||||
return info.section(" ",1,1);
|
||||
}
|
||||
|
||||
//Check if a device is wireless or not
|
||||
bool NetDevice::isWireless(){
|
||||
struct ifmediareq ifm;
|
||||
memset(&ifm, 0, sizeof(struct ifmediareq));
|
||||
|
||||
strncpy(ifm.ifm_name, name.toLocal8Bit(), IFNAMSIZ);
|
||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
ioctl(s, SIOCGIFMEDIA, &ifm);
|
||||
|
||||
return IFM_TYPE(ifm.ifm_active) == IFM_IEEE80211;
|
||||
}
|
||||
|
||||
//Get the parent device (if this is a wireless wlan)
|
||||
QString NetDevice::getWifiParent(){
|
||||
if(!name.contains("wlan")){ return ""; }
|
||||
return General::sysctl("net.wlan." + QString::number(this->devNum()) + ".%parent");
|
||||
}
|
||||
|
||||
//See if the device is setup to use DHCP
|
||||
bool NetDevice::usesDHCP(){
|
||||
//The system does not keep track of how the device's address was assigned
|
||||
// so the closest we can get to this is to see if the system is setup to use
|
||||
// DHCP on startup (in /etc/rc.conf) (Ken Moore - 6/24/15)
|
||||
return !Network::readRcConf().filter(name).filter("DHCP").isEmpty();
|
||||
}
|
||||
|
||||
//See if the device is currently in use
|
||||
bool NetDevice::isUp(){
|
||||
struct ifreq ifr;
|
||||
memset(&ifr, 0, sizeof(struct ifreq));
|
||||
|
||||
strncpy(ifr.ifr_name, name.toLocal8Bit(), IFNAMSIZ);
|
||||
int s = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
|
||||
ioctl(s, SIOCGIFFLAGS, &ifr);
|
||||
|
||||
return (ifr.ifr_flags & IFF_UP) ? 1 : 0;
|
||||
}
|
||||
|
||||
//Determine the number of packets received by the device
|
||||
long NetDevice::packetsRx(){
|
||||
int mib[6];
|
||||
size_t len;
|
||||
char *buf;
|
||||
struct if_msghdr *ifm;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = AF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_LINK;
|
||||
mib[4] = NET_RT_IFLIST;
|
||||
mib[5] = if_nametoindex(name.toLocal8Bit());
|
||||
|
||||
//First find the size of the return, so we can adjust buf accordingly
|
||||
sysctl(mib, 6, NULL, &len, NULL, 0);
|
||||
buf = (char *) malloc(len);
|
||||
sysctl(mib, 6, buf, &len, NULL, 0);
|
||||
|
||||
ifm = (if_msghdr *) buf;
|
||||
|
||||
return ifm->ifm_data.ifi_ipackets;
|
||||
}
|
||||
|
||||
//Determine the number of packets transmitted by the device
|
||||
long NetDevice::packetsTx(){
|
||||
int mib[6];
|
||||
size_t len;
|
||||
char *buf;
|
||||
struct if_msghdr *ifm;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = AF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_LINK;
|
||||
mib[4] = NET_RT_IFLIST;
|
||||
mib[5] = if_nametoindex(name.toLocal8Bit());
|
||||
|
||||
//First find the size of the return, so we can adjust buf accordingly
|
||||
sysctl(mib, 6, NULL, &len, NULL, 0);
|
||||
buf = (char *) malloc(len);
|
||||
sysctl(mib, 6, buf, &len, NULL, 0);
|
||||
|
||||
ifm = (if_msghdr *) buf;
|
||||
|
||||
return ifm->ifm_data.ifi_opackets;
|
||||
}
|
||||
|
||||
//Determine the number of errors received
|
||||
long NetDevice::errorsRx(){
|
||||
int mib[6];
|
||||
size_t len;
|
||||
char *buf;
|
||||
struct if_msghdr *ifm;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = AF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_LINK;
|
||||
mib[4] = NET_RT_IFLIST;
|
||||
mib[5] = if_nametoindex(name.toLocal8Bit());
|
||||
|
||||
//First find the size of the return, so we can adjust buf accordingly
|
||||
sysctl(mib, 6, NULL, &len, NULL, 0);
|
||||
buf = (char *) malloc(len);
|
||||
sysctl(mib, 6, buf, &len, NULL, 0);
|
||||
|
||||
ifm = (if_msghdr *) buf;
|
||||
|
||||
return ifm->ifm_data.ifi_ierrors;
|
||||
}
|
||||
|
||||
//Determine the number of errors transmitted
|
||||
long NetDevice::errorsTx(){
|
||||
int mib[6];
|
||||
size_t len;
|
||||
char *buf;
|
||||
struct if_msghdr *ifm;
|
||||
|
||||
mib[0] = CTL_NET;
|
||||
mib[1] = AF_ROUTE;
|
||||
mib[2] = 0;
|
||||
mib[3] = AF_LINK;
|
||||
mib[4] = NET_RT_IFLIST;
|
||||
mib[5] = if_nametoindex(name.toLocal8Bit());
|
||||
|
||||
//First find the size of the return, so we can adjust buf accordingly
|
||||
sysctl(mib, 6, NULL, &len, NULL, 0);
|
||||
buf = (char *) malloc(len);
|
||||
sysctl(mib, 6, buf, &len, NULL, 0);
|
||||
|
||||
ifm = (if_msghdr *) buf;
|
||||
|
||||
return ifm->ifm_data.ifi_oerrors;
|
||||
}
|
||||
|
||||
//=========================
|
||||
// SETTING FUNCTIONS (requires root)
|
||||
//=========================
|
||||
void NetDevice::setUp(bool up){
|
||||
//This only sets it up/down for the current session - does not change usage on next boot
|
||||
General::RunCommand("ifconfig "+name+" "+ (up ? "up": "down") );
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
CONFIG += c++11
|
||||
QT += core network
|
||||
|
||||
TARGET=sysadm
|
||||
target.path = /usr/local/lib
|
||||
|
||||
#DESTDIR= $$_PRO_FILE_PWD_
|
||||
|
||||
TEMPLATE = lib
|
||||
LANGUAGE = C++
|
||||
VERSION = 1.0.0
|
||||
|
||||
HEADERS += sysadm-global.h \
|
||||
sysadm-general.h \
|
||||
sysadm-iocage.h \
|
||||
sysadm-lifepreserver.h \
|
||||
sysadm-network.h \
|
||||
sysadm-firewall.h \
|
||||
sysadm-servicemanager.h\
|
||||
sysadm-systeminfo.h\
|
||||
sysadm-update.h \
|
||||
sysadm-usermanager.h
|
||||
|
||||
SOURCES += NetDevice.cpp \
|
||||
sysadm-general.cpp \
|
||||
sysadm-iocage.cpp \
|
||||
sysadm-lifepreserver.cpp \
|
||||
sysadm-network.cpp \
|
||||
sysadm-firewall.cpp \
|
||||
sysadm-servicemanager.cpp \
|
||||
sysadm-systeminfo.cpp \
|
||||
sysadm-update.cpp \
|
||||
sysadm-usermanager.cpp
|
||||
|
||||
include.path=/usr/local/include/
|
||||
include.files=sysadm-*.h
|
||||
|
||||
INSTALLS += target include
|
||||
|
||||
QMAKE_LIBDIR = /usr/local/lib/qt5 /usr/local/lib
|
||||
@@ -1,264 +0,0 @@
|
||||
//===========================================
|
||||
// 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-firewall.h"
|
||||
#include "sysadm-general.h"
|
||||
#include <QtCore>
|
||||
#include <algorithm>
|
||||
|
||||
using namespace sysadm;
|
||||
|
||||
Firewall::Firewall()
|
||||
{
|
||||
readServicesFile();
|
||||
LoadOpenPorts();
|
||||
|
||||
firewallService = serviceManager.GetService("ipfw");
|
||||
}
|
||||
|
||||
Firewall::~Firewall()
|
||||
{
|
||||
delete portStrings;
|
||||
}
|
||||
|
||||
PortInfo Firewall::LookUpPort(int port, QString type)
|
||||
{
|
||||
//Make sure that the port is valid
|
||||
if (port < 0 || port > 65535)
|
||||
{
|
||||
PortInfo returnValue;
|
||||
returnValue.Port = -1;
|
||||
returnValue.Description = "Port out of bounds";
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
//Check to see if things have been initialized
|
||||
if(portStrings == NULL)
|
||||
readServicesFile();
|
||||
|
||||
|
||||
PortInfo returnValue;
|
||||
//the port number is valid so set it
|
||||
returnValue.Port = port;
|
||||
|
||||
//make sure that the portType is cased in lower to match the service file and
|
||||
//then store it in the returnValue, since there isn't a huge point in checking
|
||||
//the validitiy of the type since /etc/services lists more than udp/tcp
|
||||
type = type.toLower();
|
||||
returnValue.Type = type;
|
||||
|
||||
//Check to see if it's a recommended port
|
||||
returnValue.Recommended = false;
|
||||
for(int recommendedPort : recommendedPorts)
|
||||
{
|
||||
if (port == recommendedPort)
|
||||
{
|
||||
returnValue.Recommended = true;
|
||||
}
|
||||
}
|
||||
|
||||
//Check to see if the port number is listed. The format in the file
|
||||
// is portname/portType. ex.: 22/tcp
|
||||
|
||||
QStringList portList = portStrings->filter(QString::number(port) + "/" + type);
|
||||
if(portList.size() > 0)
|
||||
{
|
||||
//grab the first one, there may be duplicates due to colliding ports in the /etc/services file
|
||||
//but those are listed after the declaration for what the port officially should be used for
|
||||
QString line = portList.at(0);
|
||||
|
||||
//Split across spaces since it's whitespace delimited
|
||||
QStringList lineList = line.split(' ');
|
||||
|
||||
//the keyword associated with the port is the first element in a line
|
||||
returnValue.Keyword = lineList.at(0);
|
||||
|
||||
//if the size of the list is less than 3 then there is no description
|
||||
if(lineList.size() > 2)
|
||||
{
|
||||
QString description = lineList.at(2);
|
||||
//String the description back together from the end of the list
|
||||
for(int i = 3; i < lineList.size(); i++)
|
||||
{
|
||||
description += " " + lineList.at(i);
|
||||
}
|
||||
returnValue.Description = description;
|
||||
}
|
||||
}
|
||||
|
||||
return returnValue;
|
||||
|
||||
}
|
||||
|
||||
void Firewall::OpenPort(int port, QString type)
|
||||
{
|
||||
openports.append(LookUpPort(port,type));
|
||||
SaveOpenPorts();
|
||||
}
|
||||
|
||||
void Firewall::OpenPort(QVector<PortInfo> ports)
|
||||
{
|
||||
for(PortInfo port : ports)
|
||||
{
|
||||
openports.append(port);
|
||||
}
|
||||
SaveOpenPorts();
|
||||
}
|
||||
|
||||
void Firewall::ClosePort(int port, QString type)
|
||||
{
|
||||
openports.removeAll(LookUpPort(port,type));
|
||||
SaveOpenPorts();
|
||||
}
|
||||
|
||||
void Firewall::ClosePort(QVector<PortInfo> ports)
|
||||
{
|
||||
for(PortInfo port : ports)
|
||||
{
|
||||
openports.removeAll(port);
|
||||
}
|
||||
SaveOpenPorts();
|
||||
}
|
||||
|
||||
QVector<PortInfo> Firewall::OpenPorts()
|
||||
{
|
||||
return openports;
|
||||
|
||||
}
|
||||
|
||||
bool Firewall::IsRunning()
|
||||
{
|
||||
return General::sysctlAsInt("net.inet.ip.fw.enable") == 1;
|
||||
}
|
||||
|
||||
void Firewall::Start()
|
||||
{
|
||||
serviceManager.Enable(firewallService);
|
||||
serviceManager.Start(firewallService);
|
||||
}
|
||||
|
||||
void Firewall::Stop()
|
||||
{
|
||||
serviceManager.Enable(firewallService);
|
||||
serviceManager.Stop(firewallService);
|
||||
}
|
||||
|
||||
void Firewall::Restart()
|
||||
{
|
||||
serviceManager.Enable(firewallService);
|
||||
serviceManager.Restart(firewallService);
|
||||
}
|
||||
|
||||
void Firewall::Enable()
|
||||
{
|
||||
serviceManager.Enable(firewallService);
|
||||
}
|
||||
|
||||
void Firewall::Disable()
|
||||
{
|
||||
serviceManager.Disable(firewallService);
|
||||
}
|
||||
|
||||
void Firewall::RestoreDefaults()
|
||||
{
|
||||
const QString ipfwrules = "/etc/ipfw.rules";
|
||||
const QString ipfwrulesprevious = ipfwrules + ".previous";
|
||||
|
||||
const QString ipfwopenports = "/etc/ipfw.openports";
|
||||
const QString ipfwopenportsprevious = ipfwopenports + ".previous";
|
||||
|
||||
//QFile has a rename command that acts like move, however it won't
|
||||
//clobber a file if it already exists, so we have to check if there
|
||||
//already is a .previous and if so delete it before moving the file
|
||||
//to .previous
|
||||
|
||||
//move the files out of the way
|
||||
if(QFile::exists(ipfwrulesprevious))
|
||||
QFile::remove(ipfwrulesprevious);
|
||||
QFile::rename(ipfwrules,ipfwrulesprevious);
|
||||
|
||||
if(QFile::exists(ipfwopenportsprevious))
|
||||
QFile::remove(ipfwopenportsprevious);
|
||||
QFile::rename(ipfwopenports,ipfwopenportsprevious);
|
||||
|
||||
|
||||
//refresh/restart the rules files
|
||||
QStringList args;
|
||||
args << "/usr/local/share/pcbsd/scripts/reset-firewall";
|
||||
General::RunCommand("sh",args);
|
||||
|
||||
LoadOpenPorts();
|
||||
}
|
||||
|
||||
void Firewall::readServicesFile()
|
||||
{
|
||||
portStrings = new QStringList();
|
||||
|
||||
// /etc/services contains a file that lists the various port numbers
|
||||
// and their descriptions
|
||||
QFile* services = new QFile("/etc/services");
|
||||
services->open(QFile::ReadOnly);
|
||||
while(!services->atEnd())
|
||||
{
|
||||
QString line = services->readLine();
|
||||
//jump down past the comments
|
||||
if(line[0] == '#' || line.simplified().isEmpty())
|
||||
continue;
|
||||
|
||||
//remove all of the extraneous whitespace in the line
|
||||
line = line.simplified();
|
||||
|
||||
portStrings->append(line);
|
||||
}
|
||||
services->close();
|
||||
delete services;
|
||||
}
|
||||
|
||||
void Firewall::LoadOpenPorts()
|
||||
{
|
||||
openports.clear();
|
||||
QFile file("/etc/ipfw.openports");
|
||||
if( file.open(QIODevice::ReadOnly) ){
|
||||
QTextStream in(&file);
|
||||
while( !in.atEnd() ){
|
||||
QString line = in.readLine();
|
||||
if(line.startsWith("#") || line.simplified().isEmpty()){ continue; }
|
||||
//File format: "<type> <port>" (nice and simple)
|
||||
openports.append(LookUpPort(line.section(" ",1,1).toInt(),line.section(" ",0,0)));
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
//order them in ascending order by port then port type
|
||||
std::sort(openports.begin(),openports.end());
|
||||
}
|
||||
|
||||
void Firewall::SaveOpenPorts()
|
||||
{
|
||||
//Convert to file format
|
||||
std::sort(openports.begin(), openports.end()); //make sure they are still sorted by port
|
||||
QStringList fileout;
|
||||
for(PortInfo port : openports){
|
||||
fileout.append("#" + port.Keyword + ": " + port.Description + "\n" +
|
||||
port.Type +" "+QString::number(port.Port));
|
||||
}
|
||||
//Always make sure that the file always ends with a newline
|
||||
if(!fileout.isEmpty()){ fileout << ""; }
|
||||
//Save to file
|
||||
QFile file("/etc/ipfw.openports");
|
||||
if( file.open(QIODevice::WriteOnly | QIODevice::Truncate) ){
|
||||
QTextStream out(&file);
|
||||
out << fileout.join("\n");
|
||||
file.close();
|
||||
}
|
||||
//Re-load/start rules (just in case - it is a smart script)
|
||||
if(IsRunning())
|
||||
{
|
||||
QStringList args;
|
||||
args << "/usr/local/share/pcbsd/scripts/reset-firewall";
|
||||
General::RunCommand("sh",args);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,135 +0,0 @@
|
||||
//===========================================
|
||||
// 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 PORTLOOKUP_H
|
||||
#define PORTLOOKUP_H
|
||||
#include <QtCore>
|
||||
#include <tuple>
|
||||
#include "sysadm-servicemanager.h"
|
||||
namespace sysadm
|
||||
{
|
||||
struct PortInfo{
|
||||
int Port;
|
||||
QString Type;
|
||||
QString Keyword;
|
||||
QString Description;
|
||||
bool Recommended;
|
||||
friend bool operator<(const PortInfo lhs, const PortInfo rhs){
|
||||
return std::tie(lhs.Port,lhs.Type) < std::tie(rhs.Port,rhs.Type);
|
||||
}
|
||||
friend bool operator>(const PortInfo lhs, const PortInfo rhs)
|
||||
{ return rhs < lhs;}
|
||||
friend bool operator==(const PortInfo lhs, const PortInfo rhs)
|
||||
{
|
||||
return lhs.Port == rhs.Port && lhs.Type == rhs.Type;
|
||||
}
|
||||
friend bool operator !=(const PortInfo lhs, const PortInfo rhs)
|
||||
{ return !(lhs == rhs);}
|
||||
};
|
||||
|
||||
const static QVector<int> recommendedPorts = {22, 80};
|
||||
class Firewall
|
||||
{
|
||||
|
||||
public:
|
||||
///#section: ctors dtors
|
||||
Firewall();
|
||||
~Firewall();
|
||||
///#endsection
|
||||
|
||||
///#section: port commands
|
||||
/**
|
||||
* @description Returns a structure containing information about the port
|
||||
* including its port type, keyword, description, and whether it's a
|
||||
* recommended port
|
||||
*
|
||||
* @param number a port number between 0 and 2^16 - 1
|
||||
* @param type specify whether the port is tdp, udp, etc
|
||||
*
|
||||
* @ErrorConditions Port Number is set to -1 and a description of the error is stored in the description variable
|
||||
*/
|
||||
PortInfo LookUpPort(int number, QString type);
|
||||
/**
|
||||
* @brief Opens a port
|
||||
* @param number a port number between 0 and 2^16 -1
|
||||
* @param type specify whether the port is tdp, udp, etc
|
||||
*/
|
||||
void OpenPort(int number, QString type);
|
||||
|
||||
/**
|
||||
* @brief Opens a set of ports
|
||||
* @param ports a vector of ports to open
|
||||
*/
|
||||
void OpenPort(QVector<PortInfo> ports);
|
||||
|
||||
/**
|
||||
* @brief ClosePort closes a port
|
||||
* @param number a port number between 0 and 2^16 -1
|
||||
* @param type specify whether the port is tdp, udp, etc
|
||||
*/
|
||||
void ClosePort(int number, QString type);
|
||||
|
||||
/**
|
||||
* @brief ClosePort closes a set of ports
|
||||
* @param ports a vector of ports to close
|
||||
*/
|
||||
void ClosePort(QVector<PortInfo> ports);
|
||||
|
||||
/**
|
||||
* @brief finds a list of ports that are open gets the info about them
|
||||
* and returns them
|
||||
* @return a QVector of the open ports
|
||||
*/
|
||||
QVector<PortInfo> OpenPorts();
|
||||
///#endsection
|
||||
|
||||
///#section: firewall commands
|
||||
/**
|
||||
* @brief Checks to see if the firewall is running
|
||||
* @return true if the firewall is running, false if not
|
||||
*/
|
||||
bool IsRunning();
|
||||
/**
|
||||
* @brief Starts the firewall
|
||||
*/
|
||||
void Start();
|
||||
/**
|
||||
* @brief Stops the firewall
|
||||
*/
|
||||
void Stop();
|
||||
/**
|
||||
* @brief Restarts the firewall
|
||||
*/
|
||||
void Restart();
|
||||
/**
|
||||
* @brief Enables the firewall in rc.conf, Start() will automatically enable the firewall
|
||||
*/
|
||||
void Enable();
|
||||
/**
|
||||
* @brief Disables the firewall in rc.conf use after Stop() to completely disable
|
||||
*/
|
||||
void Disable();
|
||||
/**
|
||||
* @brief Restores the Default Configuration
|
||||
*/
|
||||
void RestoreDefaults();
|
||||
///#endsection
|
||||
|
||||
private:
|
||||
void readServicesFile();
|
||||
QStringList* portStrings;
|
||||
|
||||
QVector<PortInfo> openports;
|
||||
|
||||
void LoadOpenPorts();
|
||||
void SaveOpenPorts();
|
||||
|
||||
ServiceManager serviceManager;
|
||||
Service firewallService;
|
||||
};
|
||||
}
|
||||
#endif // PORTLOOKUP_H
|
||||
|
||||
@@ -1,250 +0,0 @@
|
||||
//===========================================
|
||||
// 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-general.h"
|
||||
//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h
|
||||
|
||||
#include "sysadm-global.h"
|
||||
|
||||
using namespace sysadm;
|
||||
//=================
|
||||
// RunCommand() variations
|
||||
//=================
|
||||
//Note: environment changes should be listed as such: <variable>=<value>
|
||||
|
||||
//Return CLI output (and success/failure)
|
||||
QString General::RunCommand(bool &success, QString command, QStringList arguments, QString workdir, QStringList env){
|
||||
QProcess proc;
|
||||
proc.setProcessChannelMode(QProcess::MergedChannels); //need output
|
||||
//First setup the process environment as necessary
|
||||
QProcessEnvironment PE = QProcessEnvironment::systemEnvironment();
|
||||
if(!env.isEmpty()){
|
||||
for(int i=0; i<env.length(); i++){
|
||||
if(!env[i].contains("=")){ continue; }
|
||||
PE.insert(env[i].section("=",0,0), env[i].section("=",1,100));
|
||||
}
|
||||
}
|
||||
proc.setProcessEnvironment(PE);
|
||||
//if a working directory is specified, check it and use it
|
||||
if(!workdir.isEmpty()){
|
||||
proc.setWorkingDirectory(workdir);
|
||||
}
|
||||
//Now run the command (with any optional arguments)
|
||||
if(arguments.isEmpty()){ proc.start(command); }
|
||||
else{ proc.start(command, arguments); }
|
||||
//Wait for the process to finish (but don't block the event loop)
|
||||
while( !proc.waitForFinished(500) ){ QCoreApplication::processEvents(); }
|
||||
success = (proc.exitCode()==0); //return success/failure
|
||||
return QString(proc.readAllStandardOutput());
|
||||
}
|
||||
|
||||
QString General::RunCommand(QString command, QStringList arguments, QString workdir, QStringList env){
|
||||
//Overloaded simplification for text-only output
|
||||
bool junk = false;
|
||||
return General::RunCommand(junk,command,arguments,workdir,env);
|
||||
}
|
||||
|
||||
bool General::RunQuickCommand(QString command, QStringList arguments,QString workdir, QStringList env){
|
||||
//Overloaded simplification for success-only output
|
||||
bool success = false;
|
||||
General::RunCommand(success, command, arguments, workdir, env);
|
||||
return success;
|
||||
}
|
||||
|
||||
//=================
|
||||
// TEXT FILE INTERACTION
|
||||
//=================
|
||||
QStringList General::readTextFile(QString filepath){
|
||||
QStringList out;
|
||||
QFile file(filepath);
|
||||
if(file.open(QIODevice::Text | QIODevice::ReadOnly)){
|
||||
QTextStream in(&file);
|
||||
while(!in.atEnd()){
|
||||
out << in.readLine();
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
bool General::writeTextFile(QString filepath, QStringList contents, bool overwrite){
|
||||
//Simplification for user directory
|
||||
if(filepath.startsWith("~")){ filepath = filepath.replace(0,1,QDir::homePath()); }
|
||||
QFile file(filepath);
|
||||
//Check existance/validity
|
||||
if(file.exists() && !overwrite){ return false; }
|
||||
if(!file.exists()){
|
||||
//See if we need to create the parent directory as well
|
||||
QDir dir = QFileInfo(filepath).dir(); //get the parent directory
|
||||
if(!dir.exists()){
|
||||
if(!dir.mkpath(dir.absolutePath())){ return false; } //could not create parent directory
|
||||
}
|
||||
}
|
||||
//Make sure that something is there to be written
|
||||
// - to delete a file, use QFile::remove() instead of this function
|
||||
if(contents.isEmpty()){ contents << "\n"; }
|
||||
else if(contents.last().isEmpty()){ contents << "\n"; }
|
||||
//Now save the contents to the file
|
||||
bool ok = false;
|
||||
if( file.open(QIODevice::WriteOnly | QIODevice::Truncate) ){
|
||||
QTextStream out(&file);
|
||||
out << contents.join("\n");
|
||||
file.close();
|
||||
ok = true;
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
QString General::getConfFileValue(QString fileName, QString Key, int occur )
|
||||
{
|
||||
int found = 1;
|
||||
|
||||
QFile file( fileName );
|
||||
if ( ! file.open( QIODevice::ReadOnly ) ) {
|
||||
return QString();
|
||||
}
|
||||
|
||||
QTextStream stream( &file );
|
||||
QString line;
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
line = stream.readLine(); // line of text excluding '\n'
|
||||
line = line.section("#",0,0).trimmed(); //remove any comments
|
||||
if(line.isEmpty()){ continue; }
|
||||
int index = line.indexOf(Key, 0);
|
||||
//qDebug() << "Line:" << line << index;
|
||||
// If the KEY is not found at the start of the line, continue processing
|
||||
if(index!=0)
|
||||
continue;
|
||||
|
||||
if ( found == occur) {
|
||||
line.remove(line.indexOf(Key, 0), Key.length());
|
||||
|
||||
// Remove any quotes
|
||||
if ( line.indexOf('"') == 0 )
|
||||
line = line.remove(0, 1);
|
||||
|
||||
if ( line.indexOf('"') != -1 )
|
||||
line.truncate(line.indexOf('"'));
|
||||
|
||||
file.close();
|
||||
|
||||
return line;
|
||||
} else {
|
||||
found++;
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
return QString();
|
||||
}
|
||||
bool General::setConfFileValue(QString fileName, QString oldKey, QString newKey, int occur )
|
||||
{
|
||||
// Lets the dev save a value into a specified config file.
|
||||
// The occur value tells which occurance of "oldKey" to replace
|
||||
// If occur is set to -1, it will remove any duplicates of "oldKey"
|
||||
|
||||
//copy the original file to create a temporary file for editing
|
||||
QStringList args;
|
||||
QString oFileTmp = fileName + ".tmp";
|
||||
args << fileName << oFileTmp;
|
||||
General::RunCommand("cp",args);
|
||||
|
||||
//Continue evaluating the temporary file
|
||||
QStringList SavedFile;
|
||||
int found = 1;
|
||||
|
||||
// Load the old file, find the oldKey, remove it and replace with newKey
|
||||
QFile file( oFileTmp );
|
||||
if ( ! file.open( QIODevice::ReadOnly ) )
|
||||
return false;
|
||||
|
||||
QTextStream stream( &file );
|
||||
QString line;
|
||||
while ( !stream.atEnd() ) {
|
||||
line = stream.readLine(); // line of text excluding '\n'
|
||||
|
||||
// Key is not found at all
|
||||
if ( line.indexOf(oldKey, 0) == -1 ) {
|
||||
SavedFile << line ;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Found the key, but it is commented out, so don't worry about this line
|
||||
if ( line.trimmed().indexOf("#", 0) == 0 ) {
|
||||
SavedFile << line ;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the KEY is found, and we are just on wrong occurance, save it and continue to search
|
||||
if ( occur != -1 && found != occur ) {
|
||||
SavedFile << line ;
|
||||
found++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the KEY is found in the line and this matches the occurance that must be processed
|
||||
if ( ! newKey.isEmpty() && found == occur )
|
||||
{
|
||||
SavedFile << newKey ;
|
||||
newKey.clear();
|
||||
found++;
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the KEY is found and we just want one occurance of the key
|
||||
if ( occur == -1 && ! newKey.isEmpty() ) {
|
||||
SavedFile << newKey ;
|
||||
newKey.clear();
|
||||
found++;
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
// Didn't find the key? Write it!
|
||||
if ( ! newKey.isEmpty() )
|
||||
SavedFile << newKey;
|
||||
|
||||
|
||||
// Save the new file
|
||||
QFile fileout( oFileTmp );
|
||||
if ( ! fileout.open( QIODevice::WriteOnly ) )
|
||||
return false;
|
||||
|
||||
QTextStream streamout( &fileout );
|
||||
for (int i = 0; i < SavedFile.size(); ++i)
|
||||
streamout << SavedFile.at(i) << "\n";
|
||||
|
||||
fileout.close();
|
||||
|
||||
//Have the temporary file with new changes overwrite the original file
|
||||
args.clear();
|
||||
args << oFileTmp << fileName;
|
||||
General::RunCommand("mv",args);
|
||||
return true;
|
||||
}
|
||||
|
||||
//===========================
|
||||
// SYSCTL ACCESS (might require root)
|
||||
//===========================
|
||||
//Retrieve a text-based sysctl
|
||||
QString General::sysctl(QString var){
|
||||
char result[1000];
|
||||
size_t len = sizeof(result);
|
||||
sysctlbyname(var.toLocal8Bit(), result, &len, NULL, 0);
|
||||
result[len] = '\0';
|
||||
return QString(result);
|
||||
}
|
||||
|
||||
//Retrieve a number-based sysctl
|
||||
long long General::sysctlAsInt(QString var){
|
||||
long long result = 0;
|
||||
size_t len = sizeof(result);
|
||||
sysctlbyname(var.toLocal8Bit(), &result, &len, NULL, 0);
|
||||
return result;
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
//===========================================
|
||||
// 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 __PCBSD_LIB_UTILS_GENERAL_H
|
||||
#define __PCBSD_LIB_UTILS_GENERAL_H
|
||||
|
||||
#include "sysadm-global.h"
|
||||
|
||||
namespace sysadm{
|
||||
|
||||
class General{
|
||||
public:
|
||||
//Non-event-blocking versions of QProcess::execute() or system()
|
||||
//Note: environment changes should be listed as such: [<variable>=<value>]
|
||||
// - Both success/log of output
|
||||
static QString RunCommand(bool &success, QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() );
|
||||
// - Log output only
|
||||
static QString RunCommand(QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() );
|
||||
// - success output only
|
||||
static bool RunQuickCommand(QString command, QStringList arguments = QStringList(), QString workdir = "", QStringList env = QStringList() );
|
||||
|
||||
//File Access Functions
|
||||
static QStringList readTextFile(QString filename);
|
||||
static bool writeTextFile(QString filename, QStringList contents, bool overwrite = true);
|
||||
|
||||
/**
|
||||
* @brief getConfFileValue get the value associated with a key in a config file
|
||||
* @param fileName the file to read from
|
||||
* @param Key the key to look for
|
||||
* @param occur which occurance of the key to return, 1 = the first occurance
|
||||
* @return the value associated with the key
|
||||
*/
|
||||
static QString getConfFileValue( QString fileName, QString Key, int occur =1);
|
||||
|
||||
/**
|
||||
* @brief setConfFileValue set a value in a config file
|
||||
* @param fileName the file to write to
|
||||
* @param oldKey the key to look for
|
||||
* @param newKey the new key with it's value
|
||||
* @param occur which occurance in a file to write the key to, if set to -1 it removes all duplicates
|
||||
* @return success or failure to write the key
|
||||
*/
|
||||
static bool setConfFileValue( QString fileName, QString oldKey, QString newKey, int occur = -1 );
|
||||
|
||||
|
||||
//Retrieve a text-based sysctl
|
||||
static QString sysctl(QString var);
|
||||
//Retrieve a number-based sysctl
|
||||
static long long sysctlAsInt(QString var);
|
||||
|
||||
};
|
||||
|
||||
} //end of pcbsd namespace
|
||||
|
||||
#endif
|
||||
@@ -1,39 +0,0 @@
|
||||
//===========================================
|
||||
// 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 __PCBSD_LIB_UTILS_GENERAL_INCLUDES_H
|
||||
#define __PCBSD_LIB_UTILS_GENERAL_INCLUDES_H
|
||||
|
||||
//Qt Includes
|
||||
#include <QCoreApplication>
|
||||
#include <QDateTime>
|
||||
#include <QDir>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QJsonObject>
|
||||
#include <QJsonValue>
|
||||
#include <QProcess>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextStream>
|
||||
|
||||
//FreeBSD Includes
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysctl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <net/if.h>
|
||||
#include <net/if_dl.h>
|
||||
#include <net/if_media.h>
|
||||
|
||||
#include <ifaddrs.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h> //from "man getnetent" (network entries)
|
||||
|
||||
#endif
|
||||
@@ -1,101 +0,0 @@
|
||||
//===========================================
|
||||
// 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-general.h"
|
||||
#include "sysadm-iocage.h"
|
||||
#include "sysadm-global.h"
|
||||
|
||||
using namespace sysadm;
|
||||
|
||||
//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h
|
||||
// Return all the default iocage settings
|
||||
QJsonObject Iocage::getDefaultSettings() {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList output = General::RunCommand("iocage defaults").split("\n");
|
||||
|
||||
QJsonObject vals;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("JID") != -1 )
|
||||
continue;
|
||||
|
||||
if ( output.at(i).isEmpty() )
|
||||
break;
|
||||
|
||||
QString key = output.at(i).simplified().section("=", 0, 0);
|
||||
QString value = output.at(i).simplified().section("=", 1, 1);
|
||||
|
||||
vals.insert(key, value);
|
||||
}
|
||||
|
||||
retObject.insert("defaults", vals);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// List the jails on the box
|
||||
QJsonObject Iocage::getJailSettings(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("jail") ) {
|
||||
retObject.insert("error", "Missing required keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the key values
|
||||
QString jail = jsin.value("jail").toString();
|
||||
|
||||
QStringList output = General::RunCommand("iocage get all " + jail).split("\n");
|
||||
|
||||
QJsonObject vals;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("JID") != -1 )
|
||||
continue;
|
||||
|
||||
if ( output.at(i).isEmpty() )
|
||||
break;
|
||||
|
||||
QString key = output.at(i).simplified().section(":", 0, 0);
|
||||
QString value = output.at(i).simplified().section(":", 1, 1);
|
||||
|
||||
vals.insert(key, value);
|
||||
}
|
||||
|
||||
retObject.insert(jail, vals);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// List the jails on the box
|
||||
QJsonObject Iocage::listJails() {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList output = General::RunCommand("iocage list").split("\n");
|
||||
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("JID") != -1 )
|
||||
continue;
|
||||
|
||||
if ( output.at(i).isEmpty() )
|
||||
break;
|
||||
|
||||
QJsonObject jail;
|
||||
QString line = output.at(i).simplified();
|
||||
QString uuid = line.section(" ", 1, 1);
|
||||
|
||||
jail.insert("jid", line.section(" ", 0, 0));
|
||||
jail.insert("boot", line.section(" ", 2, 2));
|
||||
jail.insert("state", line.section(" ", 3, 3));
|
||||
jail.insert("tag", line.section(" ", 4, 4));
|
||||
jail.insert("type", line.section(" ", 5, 5));
|
||||
|
||||
retObject.insert(uuid, jail);
|
||||
}
|
||||
|
||||
return retObject;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
//===========================================
|
||||
// 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 __PCBSD_LIB_UTILS_IOCAGE_H
|
||||
#define __PCBSD_LIB_UTILS_IOCAGE_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include "sysadm-global.h"
|
||||
|
||||
namespace sysadm{
|
||||
|
||||
class Iocage{
|
||||
public:
|
||||
static QJsonObject getDefaultSettings();
|
||||
static QJsonObject getJailSettings(QJsonObject);
|
||||
static QJsonObject listJails();
|
||||
};
|
||||
|
||||
} //end of pcbsd namespace
|
||||
|
||||
#endif
|
||||
@@ -1,665 +0,0 @@
|
||||
//===========================================
|
||||
// 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-general.h"
|
||||
#include "sysadm-lifepreserver.h"
|
||||
#include "sysadm-global.h"
|
||||
|
||||
using namespace sysadm;
|
||||
|
||||
//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h
|
||||
|
||||
// Add a new replication target
|
||||
QJsonObject LifePreserver::addReplication(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString host, user, port, password, ldataset, rdataset, frequency;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("host")
|
||||
|| ! keys.contains("user")
|
||||
|| ! keys.contains("port")
|
||||
|| ! keys.contains("password")
|
||||
|| ! keys.contains("dataset")
|
||||
|| ! keys.contains("remotedataset")
|
||||
|| ! keys.contains("frequency") ) {
|
||||
retObject.insert("error", "Missing required keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the key values
|
||||
host = jsin.value("host").toString();
|
||||
user = jsin.value("user").toString();
|
||||
port = jsin.value("port").toString();
|
||||
password = jsin.value("password").toString();
|
||||
ldataset = jsin.value("dataset").toString();
|
||||
rdataset = jsin.value("remotedataset").toString();
|
||||
frequency = jsin.value("frequency").toString();
|
||||
|
||||
// Make sure we have the dataset / snap key(s)
|
||||
if ( host.isEmpty()
|
||||
|| user.isEmpty()
|
||||
|| port.isEmpty()
|
||||
|| password.isEmpty()
|
||||
|| ldataset.isEmpty()
|
||||
|| rdataset.isEmpty()
|
||||
|| frequency.isEmpty() ) {
|
||||
retObject.insert("error", "Empty dataset or snap keys ");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Run the command with the SSHPASS env variable set
|
||||
QStringList output;
|
||||
output = General::RunCommand("lpreserver", QStringList() << "replicate" << "add"
|
||||
<< host
|
||||
<< user
|
||||
<< port
|
||||
<< ldataset
|
||||
<< rdataset
|
||||
<< frequency, "", QStringList() << "SSHPASS=" + password ).split("\n");
|
||||
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Got to the end, return the good json
|
||||
QJsonObject values;
|
||||
values.insert("host", host);
|
||||
values.insert("user", user);
|
||||
values.insert("port", port);
|
||||
values.insert("ldataset", ldataset);
|
||||
values.insert("rdataset", rdataset);
|
||||
values.insert("frequency", frequency);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// Re-init the LP replication target
|
||||
QJsonObject LifePreserver::initReplication(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString dset, rhost;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if(! keys.contains("dataset") || ! keys.contains("host")){
|
||||
retObject.insert("error", "Missing dataset or host key");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Check which pool we are looking at
|
||||
dset = jsin.value("dataset").toString();
|
||||
rhost = jsin.value("host").toString();
|
||||
|
||||
// Make sure we have the pool key
|
||||
if ( dset.isEmpty() || rhost.isEmpty()) {
|
||||
retObject.insert("error", "Missing dataset or host key");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// TODO - This command can take a LONG TIME. Find a way to queue / background it and return an event
|
||||
// via websockets later, or block here and return when finished if this is REST
|
||||
QStringList output = General::RunCommand("lpreserver replicate init " + dset + " " + rhost).split("\n");
|
||||
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
QJsonObject values;
|
||||
values.insert("dataset", dset);
|
||||
values.insert("host", rhost);
|
||||
return values;
|
||||
}
|
||||
|
||||
// Build list of scheduled cron snapshot jobs
|
||||
QJsonObject LifePreserver::listCron() {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList output = General::RunCommand("lpreserver listcron").split("\n");
|
||||
QList<QStringList> snaps;
|
||||
|
||||
// Parse the output
|
||||
bool inSnapSection = false;
|
||||
bool inScrubSection = false;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("-----------------") != -1 ) {
|
||||
inSnapSection = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inSnapSection)
|
||||
continue;
|
||||
|
||||
if ( output.at(i).indexOf("Pools scheduled for scrub") != -1 ) {
|
||||
inScrubSection = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( output.at(i).isEmpty() || output.at(i).indexOf("-----------------") != -1 )
|
||||
continue;
|
||||
|
||||
if ( inSnapSection && ! inScrubSection ) {
|
||||
// Breakdown this cron job
|
||||
QString pool = output.at(i).section("-", 0, 0).simplified();
|
||||
QString freq = output.at(i).section("-", 1, 1).simplified();
|
||||
QString keep = output.at(i).section("-", 2, 2).simplified().replace("total: ", "");
|
||||
|
||||
QJsonObject values;
|
||||
values.insert("schedule", freq);
|
||||
values.insert("keep", keep);
|
||||
retObject.insert(pool, values);
|
||||
} else if (inSnapSection && inScrubSection ) {
|
||||
// Add a cron scrub
|
||||
QString pool = output.at(i).section("-", 0, 0).simplified();
|
||||
QString freq = output.at(i).section("-", 1, 1).simplified().replace(" ", "");
|
||||
qDebug() << "Found scrub:" << pool << freq;
|
||||
|
||||
QJsonObject values;
|
||||
QStringList keys = retObject.keys();
|
||||
if( keys.contains(pool)){
|
||||
// We have an existing pool object, add it
|
||||
values = retObject[pool].toObject();
|
||||
retObject.remove(pool);
|
||||
values.insert("scrub", freq);
|
||||
retObject.insert(pool, values);
|
||||
} else {
|
||||
// Add a new pool object with the scrub
|
||||
values.insert("scrub", freq);
|
||||
retObject.insert(pool, values);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Return a list of replication targets
|
||||
QJsonObject LifePreserver::listReplication() {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList output = General::RunCommand("lpreserver replicate list").split("\n");
|
||||
QStringList setitems;
|
||||
QString tmpkey;
|
||||
QRegExp sep("\\s+");
|
||||
|
||||
// Parse the output
|
||||
bool inSection = false;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("-----------------") != -1 ) {
|
||||
inSection = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inSection)
|
||||
continue;
|
||||
|
||||
if ( output.at(i).isEmpty() || output.at(i).indexOf("-----------------") != -1 )
|
||||
break;
|
||||
|
||||
// Breakdown the settings
|
||||
QJsonObject values;
|
||||
tmpkey = "";
|
||||
QString dset, rdset, user, host, port, parseline, time;
|
||||
dset = output.at(i).section(sep, 0, 0).simplified();
|
||||
parseline = output.at(i).section(sep, 2, 2).simplified();
|
||||
user = parseline.section("@", 0, 0);
|
||||
host = parseline.section("@", 1, 1).section("[", 0, 0);
|
||||
port = parseline.section("@", 1, 1).section("[", 1, 1).section("]", 0, 0);
|
||||
rdset = parseline.section(":", 1, 1);
|
||||
time = output.at(i).section(sep, 4, 4).simplified();
|
||||
|
||||
values.insert("dataset", dset);
|
||||
values.insert("user", user);
|
||||
values.insert("port", port);
|
||||
values.insert("host", host);
|
||||
values.insert("rdset", rdset);
|
||||
values.insert("frequency", time);
|
||||
retObject.insert(dset + "->" + host, values);
|
||||
}
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Return a list of snapshots on a particular pool / dataset
|
||||
QJsonObject LifePreserver::listSnap(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString pool;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if(! keys.contains("pool")){
|
||||
retObject.insert("error", "Missing pool key");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Check which pool we are looking at
|
||||
pool = jsin.value("pool").toString();
|
||||
|
||||
// Make sure we have the pool key
|
||||
if ( pool.isEmpty() ) {
|
||||
retObject.insert("error", "Missing pool key");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
QStringList output = General::RunCommand("lpreserver listsnap " + pool ).split("\n");
|
||||
QList<QStringList> snaps;
|
||||
QStringList snapitems;
|
||||
QRegExp sep("\\s+");
|
||||
|
||||
// Parse the output
|
||||
bool inSection = false;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("-----------------") != -1 ) {
|
||||
inSection = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inSection)
|
||||
continue;
|
||||
|
||||
if ( output.at(i).isEmpty() || output.at(i).indexOf("-----------------") != -1 )
|
||||
break;
|
||||
|
||||
// Breakdown this snapshot
|
||||
snapitems.clear();
|
||||
snapitems << output.at(i).section(sep, 0, 0).simplified();
|
||||
snapitems << output.at(i).section(sep, 1, -1).simplified();
|
||||
|
||||
QJsonObject values;
|
||||
values.insert("comment", snapitems.at(1));
|
||||
retObject.insert(snapitems.at(0), values);
|
||||
}
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Remove a replication task
|
||||
QJsonObject LifePreserver::removeReplication(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString dataset, host;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if(! keys.contains("dataset") || ! keys.contains("host")){
|
||||
retObject.insert("error", "Requires dataset and host keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the dataset / host
|
||||
dataset = jsin.value("dataset").toString();
|
||||
host = jsin.value("host").toString();
|
||||
|
||||
// Make sure we have the dataset / host key(s)
|
||||
if ( dataset.isEmpty() || host.isEmpty() ) {
|
||||
retObject.insert("error", "Empty dataset or host keys ");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
QStringList output;
|
||||
output = General::RunCommand("lpreserver replicate remove " + dataset + " " + host).split("\n");
|
||||
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Got to the end, return the good json
|
||||
QJsonObject values;
|
||||
values.insert("dataset", dataset);
|
||||
values.insert("host", host);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// Remove a snapshot
|
||||
QJsonObject LifePreserver::removeSnapshot(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString dataset, snap;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if(! keys.contains("dataset") || ! keys.contains("snap")){
|
||||
retObject.insert("error", "Requires dataset and snap keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the dataset / snap
|
||||
dataset = jsin.value("dataset").toString();
|
||||
snap = jsin.value("snap").toString();
|
||||
|
||||
// Make sure we have the dataset / snap key(s)
|
||||
if ( dataset.isEmpty() || snap.isEmpty() ) {
|
||||
retObject.insert("error", "Empty dataset or snap keys ");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
QStringList output;
|
||||
output = General::RunCommand("lpreserver rmsnap " + dataset + " " + snap).split("\n");
|
||||
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Got to the end, return the good json
|
||||
QJsonObject values;
|
||||
values.insert("dataset", dataset);
|
||||
values.insert("snap", snap);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// Run a replication task
|
||||
QJsonObject LifePreserver::runReplication(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString dataset, host;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if(! keys.contains("dataset") || ! keys.contains("host")){
|
||||
retObject.insert("error", "Requires dataset and host keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the dataset / host
|
||||
dataset = jsin.value("dataset").toString();
|
||||
host = jsin.value("host").toString();
|
||||
|
||||
// Make sure we have the dataset / host key(s)
|
||||
if ( dataset.isEmpty() || host.isEmpty() ) {
|
||||
retObject.insert("error", "Empty dataset or host keys ");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
QStringList output;
|
||||
output = General::RunCommand("lpreserver replicate run " + dataset + " " + host).split("\n");
|
||||
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Got to the end, return the good json
|
||||
QJsonObject values;
|
||||
values.insert("dataset", dataset);
|
||||
values.insert("host", host);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// Revert to a snapshot
|
||||
QJsonObject LifePreserver::revertSnapshot(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString dataset, snap;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if(! keys.contains("dataset") || ! keys.contains("snap")){
|
||||
retObject.insert("error", "Requires dataset and snap keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Get the dataset / snap
|
||||
dataset = jsin.value("dataset").toString();
|
||||
snap = jsin.value("snap").toString();
|
||||
|
||||
// Make sure we have the dataset / snap key(s)
|
||||
if ( dataset.isEmpty() || snap.isEmpty() ) {
|
||||
retObject.insert("error", "Empty dataset or snap keys ");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
QStringList output;
|
||||
output = General::RunCommand("lpreserver revertsnap " + dataset + " " + snap).split("\n");
|
||||
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Got to the end, return the good json
|
||||
QJsonObject values;
|
||||
values.insert("dataset", dataset);
|
||||
values.insert("snap", snap);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
// Save system-wide settings
|
||||
QJsonObject LifePreserver::saveSettings(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString warn, email, emailopts, recursive;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if(! keys.contains("duwarn") && ! keys.contains("email") && ! keys.contains("emailopts") && !keys.contains("recursive")){
|
||||
retObject.insert("error", "Requires duwarn, email, emailopts or recursive to be set!");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
QJsonObject values;
|
||||
QStringList output;
|
||||
|
||||
// Get the settings
|
||||
if ( keys.contains("duwarn") ) {
|
||||
warn = jsin.value("duwarn").toString();
|
||||
output = General::RunCommand("lpreserver set duwarn " + warn).split("\n");
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
values.insert("duwarn", warn);
|
||||
}
|
||||
if ( keys.contains("email") ) {
|
||||
email = jsin.value("email").toString();
|
||||
output = General::RunCommand("lpreserver set email " + email).split("\n");
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
values.insert("email", email);
|
||||
}
|
||||
if ( keys.contains("emailopts") ) {
|
||||
emailopts = jsin.value("emailopts").toString();
|
||||
output = General::RunCommand("lpreserver set emailopts " + emailopts.toUpper()).split("\n");
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
values.insert("emailopts", emailopts);
|
||||
}
|
||||
if ( keys.contains("recursive") ) {
|
||||
recursive = jsin.value("recursive").toString();
|
||||
QString recset = "ON";
|
||||
if ( recursive.toUpper() == "FALSE" )
|
||||
recset = "OFF";
|
||||
output = General::RunCommand("lpreserver set recursive " + recset).split("\n");
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
values.insert("recursive", recursive);
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
// Schedule a new scrub routine
|
||||
QJsonObject LifePreserver::scheduleScrub(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString pool, frequency;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if(! keys.contains("pool") || ! keys.contains("frequency")){
|
||||
retObject.insert("error", "Requires pool and frequency keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Check which pool we are looking at
|
||||
pool = jsin.value("pool").toString();
|
||||
frequency = jsin.value("frequency").toString();
|
||||
|
||||
// Make sure we have the pool / frequency / keep key(s)
|
||||
if ( pool.isEmpty() || frequency.isEmpty() ) {
|
||||
retObject.insert("error", "Empty pool or frequency keys ");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
QStringList output;
|
||||
if ( frequency == "none" )
|
||||
output = General::RunCommand("lpreserver cronscrub " + pool + " stop " + frequency).split("\n");
|
||||
else
|
||||
output = General::RunCommand("lpreserver cronscrub " + pool + " start " + frequency).split("\n");
|
||||
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Got to the end, return the good json
|
||||
QJsonObject values;
|
||||
values.insert("pool", pool);
|
||||
values.insert("frequency", frequency);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
// Schedule a new snapshot routine
|
||||
QJsonObject LifePreserver::scheduleSnapshot(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
QString pool, frequency, keep;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if(! keys.contains("pool") || ! keys.contains("frequency") || ! keys.contains("keep")){
|
||||
retObject.insert("error", "Requires pool, frequency and keep keys");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Check which pool we are looking at
|
||||
pool = jsin.value("pool").toString();
|
||||
frequency = jsin.value("frequency").toString();
|
||||
keep = jsin.value("keep").toString();
|
||||
|
||||
// Make sure we have the pool / frequency / keep key(s)
|
||||
if ( pool.isEmpty() || frequency.isEmpty() || keep.isEmpty() ) {
|
||||
retObject.insert("error", "Empty pool, frequency and keep keys ");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
QStringList output;
|
||||
if ( frequency == "none" )
|
||||
output = General::RunCommand("lpreserver cronsnap " + pool + " stop " ).split("\n");
|
||||
else
|
||||
output = General::RunCommand("lpreserver cronsnap " + pool + " start " + frequency + " " + keep ).split("\n");
|
||||
|
||||
// Check for any errors
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("ERROR:") != -1 ) {
|
||||
retObject.insert("error", output.at(i));
|
||||
return retObject;
|
||||
}
|
||||
}
|
||||
|
||||
// Got to the end, return the good json
|
||||
QJsonObject values;
|
||||
values.insert("pool", pool);
|
||||
values.insert("frequency", frequency);
|
||||
values.insert("keep", keep);
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
|
||||
// Return a list of settings for life-preserver
|
||||
QJsonObject LifePreserver::settings() {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList output = General::RunCommand("lpreserver get").split("\n");
|
||||
QStringList setitems;
|
||||
QString tmpkey;
|
||||
QRegExp sep("\\s+");
|
||||
|
||||
// Parse the output
|
||||
bool inSection = false;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("-----------------") != -1 ) {
|
||||
inSection = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inSection)
|
||||
continue;
|
||||
|
||||
if ( output.at(i).isEmpty() || output.at(i).indexOf("-----------------") != -1 )
|
||||
break;
|
||||
|
||||
// Breakdown the setting we got
|
||||
tmpkey = "";
|
||||
setitems.clear();
|
||||
setitems << output.at(i).section(":", 0, 0).simplified();
|
||||
setitems << output.at(i).section(":", 1, 1).simplified();
|
||||
if ( setitems.at(0) == "Recursive mode" )
|
||||
tmpkey = "recursive";
|
||||
if ( setitems.at(0) == "E-mail notifications" )
|
||||
tmpkey = "email";
|
||||
if ( setitems.at(0) == "E-mail addresses" )
|
||||
tmpkey = "emailaddress";
|
||||
if ( setitems.at(0) == "Disk space warn at" )
|
||||
tmpkey = "diskwarn";
|
||||
|
||||
// Unknown key we dont support?
|
||||
if ( tmpkey.isEmpty() )
|
||||
continue;
|
||||
|
||||
retObject.insert(tmpkey, setitems.at(1));
|
||||
}
|
||||
|
||||
return retObject;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
//===========================================
|
||||
// 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 __PCBSD_LIB_UTILS_LIFEPRESERVER_H
|
||||
#define __PCBSD_LIB_UTILS_LIFEPRESERVER_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include "sysadm-global.h"
|
||||
|
||||
namespace sysadm{
|
||||
|
||||
class LifePreserver{
|
||||
public:
|
||||
static QJsonObject addReplication(QJsonObject jsin);
|
||||
static QJsonObject initReplication(QJsonObject jsin);
|
||||
static QJsonObject listCron();
|
||||
static QJsonObject listReplication();
|
||||
static QJsonObject listSnap(QJsonObject jsin);
|
||||
static QJsonObject removeReplication(QJsonObject jsin);
|
||||
static QJsonObject removeSnapshot(QJsonObject jsin);
|
||||
static QJsonObject revertSnapshot(QJsonObject jsin);
|
||||
static QJsonObject runReplication(QJsonObject jsin);
|
||||
static QJsonObject saveSettings(QJsonObject jsin);
|
||||
static QJsonObject scheduleSnapshot(QJsonObject jsin);
|
||||
static QJsonObject scheduleScrub(QJsonObject jsin);
|
||||
static QJsonObject settings();
|
||||
};
|
||||
|
||||
} //end of pcbsd namespace
|
||||
|
||||
#endif
|
||||
@@ -1,129 +0,0 @@
|
||||
//===========================================
|
||||
// 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-network.h"
|
||||
//PLEASE: Keep the functions in the same order as listed in pcbsd-network.h
|
||||
#include "sysadm-general.h"
|
||||
|
||||
using namespace sysadm;
|
||||
//=====================
|
||||
// NETWORK FUNCTIONS
|
||||
//=====================
|
||||
/*QList<NetworkEntry> Network::listNetworkEntries(){
|
||||
QList<NetworkEntry> out;
|
||||
netent *entry = getnetent();
|
||||
while(entry!=0){
|
||||
//Copy over this data into the output structure
|
||||
NetworkEntry tmp;
|
||||
tmp.name = QString::fromLocal8Bit(entry->n_name);
|
||||
for(int i=0; entry->n_aliases[i] != 0; i++){
|
||||
tmp.aliases << QString::fromLocal8Bit(entry->n_aliases[i]);
|
||||
}
|
||||
tmp.netnum = entry->n_net;
|
||||
out << tmp;
|
||||
//Now load the next entry
|
||||
entry = getnetent();
|
||||
}
|
||||
endnetent(); //make sure to close the file since we are finished reading it
|
||||
return out;
|
||||
}*/
|
||||
|
||||
//---------------------------------------
|
||||
QStringList Network::readRcConf(){
|
||||
static QStringList contents = QStringList();
|
||||
static QDateTime lastread;
|
||||
if(!lastread.isValid() || contents.isEmpty() || (QFileInfo("/etc/rc.conf").lastModified()> lastread) ){
|
||||
lastread = QDateTime::currentDateTime();
|
||||
contents = General::readTextFile("/etc/rc.conf");
|
||||
}
|
||||
return contents;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
NetDevSettings Network::deviceRCSettings(QString dev){
|
||||
QStringList info = Network::readRcConf().filter(dev);
|
||||
//Setup the default structure/values
|
||||
NetDevSettings set;
|
||||
set.device = dev;
|
||||
set.wifihost = set.useDHCP = set.wifisecurity = false;
|
||||
if(info.isEmpty()){ return set; } //no settings
|
||||
//Now load any info associated with this device
|
||||
for(int i=0; i<info.length(); i++){
|
||||
QString var = info[i].section("=",0,0).simplified();
|
||||
QString val = info[i].section("=",1,100).simplified();
|
||||
if(val.startsWith("\"")){ val = val.remove(1); }
|
||||
if(val.endsWith("\"")){ val.chop(1); }
|
||||
val.prepend(" "); val.append(" "); //just to make additional parsing easier later - each "variable" should have whitespace on both sides
|
||||
if( (var=="vlans_"+dev) || (var=="wlans_"+dev) ){
|
||||
set.asDevice = val;
|
||||
}else if(var==("ifconfig_"+dev)){
|
||||
QStringList vals = val.split(" ",QString::SkipEmptyParts);
|
||||
//This is the main settings line: lots of things to look for:
|
||||
if(!val.contains("DHCP")){
|
||||
//Look for the static networking values
|
||||
set.useDHCP = false;
|
||||
if(val.contains(" netmask ")){ set.staticNetmask = val.section(" netmask ",1,1).section(" ",0,0); }
|
||||
if(val.contains(" gateway ")){ set.staticGateway = val.section(" gateway ",1,1).section(" ",0,0); }
|
||||
if(val.contains(" inet ")){ set.staticIPv4 = val.section(" inet ",1,1).section(" ",0,0); }
|
||||
if(val.contains(" inet6 ")){ set.staticIPv6 = val.section(" inet6 ",1,1).section(" ",0,0); }
|
||||
/*if(set.staticIPv4.isEmpty() || set.staticIPv6.isEmpty()){
|
||||
//IPv4/6 address can sometimes not have the "inet(6)" identifier - look through the first few values as well
|
||||
QStringList vals = val.split(" ",QString::SkipEmptyParts);
|
||||
for(int v=0; v<vals.length(); v++){
|
||||
|
||||
}
|
||||
}*/
|
||||
}else{ set.useDHCP=true; } //end of DHCP check
|
||||
//Wifi Checks
|
||||
if(vals.contains("WPA")){ set.wifisecurity=true; }
|
||||
|
||||
} //end variable checks
|
||||
} //end loop over rc.conf lines
|
||||
return set;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
/*NetDevSettings Network::deviceIfconfigSettings(QString dev){
|
||||
QString info = General::RunCommand("ifconfig "+dev);
|
||||
NetDevSettings set;
|
||||
if(info.isEmpty() || info.contains("interface "+dev+"does not exist")){ return set; } //empty stucture
|
||||
//Now parse all the available info from ifconfig
|
||||
info = info.replace("\t"," ").replace("\n"," ").simplified(); //ensure that whitespace is used for parsing
|
||||
//if(info.contains("inet ")){ set.staticIPv4 = info.section("inet ",1,1).section(" ",0,0); }
|
||||
//if(info.contains("inet6 ")){ set.staticIPv6 = info.section("inet6 ",1,1).section("%",0,0); }
|
||||
set.device = dev;
|
||||
if(info.contains(" ether ")){ set.etherMac = info.section(" ether ",1,1).section(" ",0,0); }
|
||||
if(info.contains(" ssid ")){ set.wifiSSID = info.section(" ssid ",1,1).section(" ",0,0); }
|
||||
if(info.contains(" bssid ")){ set.wifiBSSID = info.section(" bssid ",1,1).section(" ",0,0); }
|
||||
if(info.contains(" country ")){ set.wifiCountry = info.section(" country ",1,1).section(" ",0,0); }
|
||||
if(info.contains(" channel ")){ set.wifiChannel = info.section(" channel ",1,1).section(" ",0,0); }
|
||||
return set;
|
||||
}*/
|
||||
|
||||
//=====================
|
||||
// NETWORK-ROOT FUNCTIONS
|
||||
//=====================
|
||||
/*bool NetworkRoot::saveNetworkEntry(NetworkEntry data){
|
||||
netent *entry = getnetbyname(data.name.toLocal8Bit());
|
||||
if(entry==0){
|
||||
//This entry does not exist yet - need to add it
|
||||
return false; //not implemented yet - add it to /etc/networks?
|
||||
}else{
|
||||
//This entry already exists, update it
|
||||
endnetent(); //Make sure to close the file when finished
|
||||
return false; //not implemented yet
|
||||
}
|
||||
}*/
|
||||
|
||||
//--------------------------------------
|
||||
bool NetworkRoot::saveRCSettings(NetDevSettings){
|
||||
return false;
|
||||
}
|
||||
|
||||
//--------------------------------------
|
||||
bool NetworkRoot::setIfconfigSettings(NetDevSettings){
|
||||
return false;
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
//===========================================
|
||||
// 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 __PCBSD_LIB_UTILS_NETWORK_H
|
||||
#define __PCBSD_LIB_UTILS_NETWORK_H
|
||||
|
||||
#include "sysadm-global.h"
|
||||
|
||||
namespace sysadm{
|
||||
|
||||
//General purpose enumeration of network encryption types
|
||||
enum NetCrypt {UNKNOWN, NONE, WEP, WPA1, WPA2, WPAE};
|
||||
|
||||
//Data structure for network entries ("/etc/networks" entries for example)
|
||||
struct NetworkEntry{
|
||||
QString name;
|
||||
QStringList aliases;
|
||||
unsigned int netnum;
|
||||
};
|
||||
|
||||
//Data structure for rc.conf settings
|
||||
struct NetDevSettings{
|
||||
QString device; //the device these settings correspond with (usually unset if there was an error)
|
||||
QString asDevice; //associated device (Example: wifi device -> wlan<num> device)
|
||||
//Wifi settings
|
||||
QString wifiCountry, wifiSSID, wifiBSSID, wifiChannel;
|
||||
bool wifihost;
|
||||
bool wifisecurity; //always recommended for wifi settings - otherwise can't connect to secure access points
|
||||
//Addressing
|
||||
bool useDHCP;
|
||||
QString staticIPv4, staticNetmask, staticIPv6; //assumes DHCP if none are set
|
||||
QString staticGateway;
|
||||
};
|
||||
|
||||
//General data class for network devices
|
||||
// Note: Sources in NetDevice.cpp
|
||||
class NetDevice{
|
||||
private:
|
||||
QString name;
|
||||
public:
|
||||
NetDevice(QString devName){ name = devName; }
|
||||
QString device(){ return name; } //full device name (wlan0)
|
||||
QString devName(); //name only (wlan)
|
||||
uint devNum(); //number only (0)
|
||||
QString ipAsString();
|
||||
QString ipv6AsString();
|
||||
QString netmaskAsString();
|
||||
QString desc();
|
||||
QString macAsString();
|
||||
//QString mediaTypeAsString();
|
||||
QString mediaStatusAsString();
|
||||
QString gatewayAsString();
|
||||
bool isWireless();
|
||||
QString getWifiParent();
|
||||
bool usesDHCP();
|
||||
bool isUp();
|
||||
long packetsRx();
|
||||
long packetsTx();
|
||||
long errorsRx();
|
||||
long errorsTx();
|
||||
|
||||
//Setting Functions (to make changes - requires root)
|
||||
void setUp(bool up); //Turn device on/off (temporary - not saved globally)
|
||||
|
||||
//Generic listing of devices
|
||||
static QStringList listNetDevices(); //probe the system for all network devices
|
||||
};
|
||||
|
||||
//General data structure for wifi access points (local or available)
|
||||
struct NetWifi{
|
||||
NetCrypt encryption;
|
||||
QString BSSID, SSID;
|
||||
};
|
||||
|
||||
|
||||
//The general-purpose class that any user/app can utilitize
|
||||
class Network{
|
||||
public:
|
||||
//static QList<NetworkEntry> listNetworkEntries();
|
||||
static QStringList readRcConf(); //use this when reading /etc/rc.conf for network stuff - prevents opening the file repeatedly
|
||||
static NetDevSettings deviceRCSettings(QString dev); //settings in rc.conf (bootup)
|
||||
//static NetDevSettings deviceIfconfigSettings(QString dev); //settings currently running
|
||||
};
|
||||
|
||||
//The class that requires overarching root permissions (usually for changes to system)
|
||||
class NetworkRoot{
|
||||
public:
|
||||
//static bool saveNetworkEntry(NetworkEntry); //**Not implemented yet**
|
||||
static bool saveRCSettings(NetDevSettings); //rc.conf settings (bootup)
|
||||
static bool setIfconfigSettings(NetDevSettings); //ifconfig settings (temporary session)
|
||||
};
|
||||
|
||||
} //end of pcbsd namespace
|
||||
|
||||
#endif
|
||||
@@ -1,172 +0,0 @@
|
||||
#include "sysadm-servicemanager.h"
|
||||
#include "sysadm-general.h"
|
||||
using namespace sysadm;
|
||||
ServiceManager::ServiceManager(QString chroot, QString ip)
|
||||
{
|
||||
this->chroot = chroot;
|
||||
this->ip = ip;
|
||||
loadServices();
|
||||
}
|
||||
|
||||
Service ServiceManager::GetService(QString serviceName)
|
||||
{
|
||||
for(Service service : services)
|
||||
{
|
||||
if(service.Name == serviceName)
|
||||
return service;
|
||||
}
|
||||
return Service();
|
||||
}
|
||||
|
||||
QVector<Service> ServiceManager::GetServices()
|
||||
{
|
||||
return services;
|
||||
}
|
||||
|
||||
void ServiceManager::Start(Service service)
|
||||
{
|
||||
// Start the process
|
||||
QString prog;
|
||||
QStringList args;
|
||||
|
||||
if ( chroot.isEmpty() ) {
|
||||
prog = "service";
|
||||
args << service.Directory;
|
||||
args << "start";
|
||||
} else {
|
||||
prog = "warden";
|
||||
args << "chroot" << ip << "service" << service.Directory << "start";
|
||||
}
|
||||
General::RunCommand(prog,args);
|
||||
}
|
||||
|
||||
void ServiceManager::Stop(Service service)
|
||||
{
|
||||
// Start the process
|
||||
QString prog;
|
||||
QStringList args;
|
||||
|
||||
if ( chroot.isEmpty() ) {
|
||||
prog = "service";
|
||||
args << service.Directory;
|
||||
args << "stop";
|
||||
} else {
|
||||
prog = "warden";
|
||||
args << "chroot" << ip << "service" << service.Directory << "stop";
|
||||
}
|
||||
General::RunCommand(prog,args);
|
||||
}
|
||||
|
||||
void ServiceManager::Restart(Service service)
|
||||
{
|
||||
QString prog;
|
||||
QStringList args;
|
||||
|
||||
if ( chroot.isEmpty() ) {
|
||||
prog = "service";
|
||||
args << service.Directory;
|
||||
args << "restart";
|
||||
} else {
|
||||
prog = "warden";
|
||||
args << "chroot" << ip << "service" << service.Directory << "restart";
|
||||
}
|
||||
General::RunCommand(prog,args);
|
||||
}
|
||||
|
||||
void ServiceManager::Enable(Service service)
|
||||
{
|
||||
General::setConfFileValue( chroot + "/etc/rc.conf", service.Tag, service.Tag + "=\"YES\"", -1);
|
||||
}
|
||||
|
||||
void ServiceManager::Disable(Service service)
|
||||
{
|
||||
General::setConfFileValue( chroot + "/etc/rc.conf", service.Tag, service.Tag + "=\"NO\"", -1);
|
||||
}
|
||||
|
||||
void ServiceManager::loadServices()
|
||||
{
|
||||
QString tmp;
|
||||
bool valid;
|
||||
Service service;
|
||||
|
||||
QStringList stringDirs;
|
||||
stringDirs << chroot + "/etc/rc.d" << chroot + "/usr/local/etc/rc.d";
|
||||
|
||||
for ( QString dir: stringDirs)
|
||||
{
|
||||
|
||||
QDir directory( dir );
|
||||
|
||||
directory.setFilter( QDir::Files );
|
||||
directory.setSorting( QDir::Name );
|
||||
|
||||
if ( directory.count() == 0 )
|
||||
return;
|
||||
|
||||
for (unsigned int i = 0; i < directory.count(); i++ )
|
||||
{
|
||||
service = Service();
|
||||
|
||||
QFile file( dir + "/" + directory[i] );
|
||||
if ( file.open( QIODevice::ReadOnly ) )
|
||||
{
|
||||
valid=false;
|
||||
service.Directory=directory[i];
|
||||
QTextStream stream( &file );
|
||||
stream.setCodec("UTF-8");
|
||||
QString line;
|
||||
while ( !stream.atEnd() )
|
||||
{
|
||||
line = stream.readLine(); // line of text excluding '\n'
|
||||
|
||||
if ( line.indexOf("name=") == 0)
|
||||
{
|
||||
valid=true;
|
||||
tmp = line.replace("name=", "");
|
||||
service.Name = tmp.replace('"', "");
|
||||
}
|
||||
if ( line.indexOf("rcvar=") == 0)
|
||||
{
|
||||
if ( tmp.isEmpty() )
|
||||
continue;
|
||||
|
||||
tmp = line.replace("rcvar=", "");
|
||||
tmp = tmp.replace('"', "");
|
||||
tmp = tmp.replace("'", "");
|
||||
tmp = tmp.replace("`", "");
|
||||
tmp = tmp.replace("$(set_rcvar)", "");
|
||||
tmp = tmp.replace("$set_rcvar", "");
|
||||
tmp = tmp.replace("set_rcvar", "");
|
||||
tmp = tmp.replace("${name}", "");
|
||||
tmp = tmp.replace("_enable", "");
|
||||
tmp = tmp.replace(" ", "");
|
||||
|
||||
if (tmp.isEmpty())
|
||||
service.Tag = service.Name + "_enable";
|
||||
else
|
||||
service.Tag = tmp;
|
||||
|
||||
if ( service.Tag.indexOf("_enable") == -1 )
|
||||
service.Tag=service.Tag + "_enable";
|
||||
break;
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
|
||||
if ( !valid || service.Tag.isEmpty() )
|
||||
continue;
|
||||
|
||||
QString cDir = dir;
|
||||
if ( ! chroot.isEmpty() )
|
||||
cDir.replace(chroot, "");
|
||||
if ( service.Tag.indexOf("$") == 0 )
|
||||
service.Tag = service.Directory + "_enable";
|
||||
if ( service.Name.indexOf("$") == 0 )
|
||||
service.Name = service.Directory;
|
||||
|
||||
services << service;
|
||||
//qDebug() << "Added Service:" << cDir << service.Directory << service.Name << service.Tag;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
#ifndef SERVICEMANAGER_H
|
||||
#define SERVICEMANAGER_H
|
||||
#include <QtCore>
|
||||
namespace sysadm{
|
||||
struct Service{
|
||||
Service()
|
||||
{
|
||||
Name = "";
|
||||
Tag = "";
|
||||
Directory = "";
|
||||
}
|
||||
|
||||
QString Name;
|
||||
QString Tag;
|
||||
QString Directory;
|
||||
};
|
||||
|
||||
class ServiceManager
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief ServiceManager constructor for service manager
|
||||
* @param chroot if we're using a chroot, the chroot to use
|
||||
* @param ip if we're in a jail the ip to use
|
||||
*/
|
||||
ServiceManager(QString chroot = "", QString ip = "");
|
||||
|
||||
/**
|
||||
* @brief GetService gets a service by it's name
|
||||
* @param serviceName the name of the service to get, use the name that would be stored in Service.Name
|
||||
* @return the service with the service name, if the service is not found it returns a blank Service
|
||||
*/
|
||||
Service GetService(QString serviceName);
|
||||
/**
|
||||
* @brief GetServices getter for the vector of services
|
||||
* @return returns the vector of services on the system
|
||||
*/
|
||||
QVector<Service> GetServices();
|
||||
|
||||
/**
|
||||
* @brief Start starts a service
|
||||
* @param service the service to start
|
||||
*/
|
||||
void Start(Service service);
|
||||
/**
|
||||
* @brief Stop stops a service
|
||||
* @param service the service to stop
|
||||
*/
|
||||
void Stop(Service service);
|
||||
/**
|
||||
* @brief Restart restarts a service
|
||||
* @param service the service to restart
|
||||
*/
|
||||
void Restart(Service service);
|
||||
|
||||
/**
|
||||
* @brief Enable enable a service
|
||||
* @param service the service to enable
|
||||
*/
|
||||
void Enable(Service service);
|
||||
/**
|
||||
* @brief Disable disable a service
|
||||
* @param service the service to disable
|
||||
*/
|
||||
void Disable(Service service);
|
||||
private:
|
||||
QVector<Service> services;
|
||||
void loadServices();
|
||||
QString chroot;
|
||||
QString ip;
|
||||
};
|
||||
}
|
||||
#endif // SERVICEMANAGER_H
|
||||
@@ -1,251 +0,0 @@
|
||||
//===========================================
|
||||
// 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-general.h"
|
||||
#include "sysadm-systeminfo.h"
|
||||
#include "sysadm-global.h"
|
||||
|
||||
using namespace sysadm;
|
||||
|
||||
//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h
|
||||
|
||||
|
||||
//Battery Availability
|
||||
QJsonObject SysInfo::batteryInfo(){
|
||||
QJsonObject retObject;
|
||||
bool ok;
|
||||
|
||||
int val = General::RunCommand("apm -l").toInt(&ok);
|
||||
if ( ok && (val >= 0 && val <= 100) ) {
|
||||
retObject.insert("battery", "true");
|
||||
} else {
|
||||
retObject.insert("battery", "false");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// We have a battery, return info about it
|
||||
//Battery Charge Level
|
||||
QString tmp;
|
||||
tmp.setNum(val);
|
||||
retObject.insert("level", tmp);
|
||||
|
||||
//Battery Charging State
|
||||
int state = General::RunCommand("apm -a").toInt(&ok);
|
||||
if ( ok && state == 0 )
|
||||
retObject.insert("status", "offline");
|
||||
else if ( ok && state == 1 )
|
||||
retObject.insert("status", "charging");
|
||||
else if ( ok && state == 2 )
|
||||
retObject.insert("status", "backup");
|
||||
else
|
||||
retObject.insert("status", "unknown");
|
||||
|
||||
int timeleft = General::RunCommand("apm -t").toInt(&ok);
|
||||
if ( ok ) {
|
||||
tmp.setNum(timeleft);
|
||||
retObject.insert("timeleft", tmp);
|
||||
} else {
|
||||
retObject.insert("timeleft", "-1");
|
||||
}
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// KPM 1-21-2016
|
||||
// This needs to be looked at, I'm not 100% sure it is returning correct busy %
|
||||
// We probably want to supply more info as well, such as user,nice,system,interrupt,idle
|
||||
QJsonObject SysInfo::cpuPercentage() {
|
||||
QJsonObject retObject;
|
||||
QString tmp;
|
||||
|
||||
//Calculate the percentage based on the kernel information directly - no extra utilities
|
||||
QStringList result = General::RunCommand("sysctl -n kern.cp_times").split(" ");
|
||||
static QStringList last = QStringList();
|
||||
if(last.isEmpty()){
|
||||
//need two ticks before it works properly
|
||||
sleep(1);
|
||||
last = result;
|
||||
result = General::RunCommand("sysctl -n kern.cp_times").split(" ");
|
||||
}
|
||||
double tot = 0;
|
||||
double roundtot;
|
||||
int cpnum = 0;
|
||||
for(int i=4; i<result.length(); i+=5){
|
||||
//The values come in blocks of 5 per CPU: [user,nice,system,interrupt,idle]
|
||||
cpnum++; //the number of CPU's accounted for (to average out at the end)
|
||||
//qDebug() <<"CPU:" << cpnum;
|
||||
long sum = 0;
|
||||
//Adjust/all the data to correspond to diffs from the previous check
|
||||
for(int j=0; j<5; j++){
|
||||
QString tmp = result[i-j];
|
||||
result[i-j] = QString::number(result[i-j].toLong()-last[i-j].toLong());
|
||||
//need the difference between last run and this one
|
||||
sum += result[i-j].toLong();
|
||||
last[i-j] = tmp; //make sure to keep the original value around for the next run
|
||||
}
|
||||
QJsonObject vals;
|
||||
roundtot = 100.0L - ( (100.0L*result[i].toLong())/sum );
|
||||
tmp.setNum(qRound(roundtot));
|
||||
vals.insert("busy", tmp );
|
||||
tmp.setNum(cpnum);
|
||||
retObject.insert("cpu" + tmp, vals);
|
||||
//Calculate the percentage used for this CPU (100% - IDLE%)
|
||||
tot += 100.0L - ( (100.0L*result[i].toLong())/sum ); //remember IDLE is the last of the five values per CPU
|
||||
}
|
||||
|
||||
// Add the total busy %
|
||||
tmp.setNum(qRound(tot/cpnum));
|
||||
retObject.insert("busytotal", tmp);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
QJsonObject SysInfo::cpuTemps() {
|
||||
// Make sure coretemp is loaded
|
||||
if ( General::RunCommand("kldstat").indexOf("coretemp") == -1 )
|
||||
General::RunCommand("kldload coretemp");
|
||||
|
||||
QJsonObject retObject;
|
||||
QStringList temps;
|
||||
temps = General::RunCommand("sysctl -ai").split("\n").filter(".temperature:");
|
||||
temps.sort();
|
||||
for(int i=0; i<temps.length(); i++){
|
||||
if(temps[i].contains(".acpi.") || temps[i].contains(".cpu")){
|
||||
retObject.insert(temps[i].section(":", 0, 0).section(".", 1,2).replace(".", "").simplified(), temps[i].section(":", 1,5).simplified());
|
||||
}else{
|
||||
//non CPU temperature - skip it
|
||||
temps.removeAt(i); i--;
|
||||
}
|
||||
}
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// ==== ExternalDevicePaths() ====
|
||||
QJsonObject SysInfo::externalDevicePaths() {
|
||||
QJsonObject retObject;
|
||||
|
||||
//Returns: QStringList[<type>::::<filesystem>::::<path>]
|
||||
//Note: <type> = [USB, HDRIVE, DVD, SDCARD, UNKNOWN]
|
||||
QStringList devs = General::RunCommand("mount").split("\n");
|
||||
|
||||
//Now check the output
|
||||
for(int i=0; i<devs.length(); i++){
|
||||
if(devs[i].startsWith("/dev/")){
|
||||
devs[i].replace("\t"," ");
|
||||
QString type = devs[i].section(" on ",0,0);
|
||||
type.remove("/dev/");
|
||||
//Determine the type of hardware device based on the dev node
|
||||
if(type.startsWith("da")){ type = "USB"; }
|
||||
else if(type.startsWith("ada")){ type = "HDRIVE"; }
|
||||
else if(type.startsWith("mmsd")){ type = "SDCARD"; }
|
||||
else if(type.startsWith("cd")||type.startsWith("acd")){ type="DVD"; }
|
||||
else{ type = "UNKNOWN"; }
|
||||
//Now put the device in the proper output format
|
||||
QString filesystem = devs[i].section("(",1,1).section(",",0,0);
|
||||
QString path = devs[i].section(" on ",1,50).section("(",0,0).simplified();
|
||||
QJsonObject vals;
|
||||
vals.insert("type",type);
|
||||
vals.insert("filesystem",filesystem);
|
||||
vals.insert("path",path);
|
||||
retObject.insert(devs[i].section(" ", 0, 0), vals);
|
||||
}else{
|
||||
//invalid device - remove it from the list
|
||||
devs.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
|
||||
// Return the devices / mounts
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Return information about memory
|
||||
QJsonObject SysInfo::memoryStats() {
|
||||
QJsonObject retObject;
|
||||
|
||||
QString tmp;
|
||||
long pageSize;
|
||||
bool ok;
|
||||
|
||||
// Get the page size
|
||||
tmp = General::RunCommand("sysctl -n vm.stats.vm.v_page_size").simplified();
|
||||
tmp.toLong(&ok);
|
||||
if ( ok )
|
||||
pageSize = tmp.toLong();
|
||||
else
|
||||
return retObject;
|
||||
|
||||
// Get the free size
|
||||
tmp = General::RunCommand("sysctl -n vm.stats.vm.v_free_count").simplified();
|
||||
tmp.toLong(&ok);
|
||||
if ( ok )
|
||||
retObject.insert("free", tmp.setNum((tmp.toLong() * pageSize) / 1024 / 1024));
|
||||
|
||||
// Get the inactive size
|
||||
tmp = General::RunCommand("sysctl -n vm.stats.vm.v_inactive_count").simplified();
|
||||
tmp.toLong(&ok);
|
||||
if ( ok )
|
||||
retObject.insert("inactive", tmp.setNum((tmp.toLong() * pageSize) / 1024 / 1024));
|
||||
|
||||
// Get the cache size
|
||||
tmp = General::RunCommand("sysctl -n vm.stats.vm.v_cache_count").simplified();
|
||||
tmp.toLong(&ok);
|
||||
if ( ok )
|
||||
retObject.insert("cache", tmp.setNum((tmp.toLong() * pageSize) / 1024 / 1024));
|
||||
|
||||
// Get the wired size
|
||||
tmp = General::RunCommand("sysctl -n vm.stats.vm.v_wire_count").simplified();
|
||||
tmp.toLong(&ok);
|
||||
if ( ok )
|
||||
retObject.insert("wired", tmp.setNum((tmp.toLong() * pageSize) / 1024 / 1024));
|
||||
|
||||
// Get the active size
|
||||
tmp = General::RunCommand("sysctl -n vm.stats.vm.v_active_count").simplified();
|
||||
tmp.toLong(&ok);
|
||||
if ( ok )
|
||||
retObject.insert("active", tmp.setNum((tmp.toLong() * pageSize) / 1024 / 1024));
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Return a bunch of various system information
|
||||
QJsonObject SysInfo::systemInfo() {
|
||||
QJsonObject retObject;
|
||||
|
||||
QString arch = General::RunCommand("uname -m").simplified();
|
||||
retObject.insert("arch", arch);
|
||||
|
||||
QString sysver = General::RunCommand("freebsd-version").simplified();
|
||||
retObject.insert("systemversion", sysver);
|
||||
|
||||
QString kernver = General::RunCommand("uname -r").simplified();
|
||||
retObject.insert("kernelversion", kernver);
|
||||
|
||||
QString kernident = General::RunCommand("uname -i").simplified();
|
||||
retObject.insert("kernelident", kernident);
|
||||
|
||||
QString host = General::RunCommand("hostname").simplified();
|
||||
retObject.insert("hostname", host);
|
||||
|
||||
QString uptime = General::RunCommand("uptime").simplified().section(" ", 1, 4).simplified().replace(",", "");
|
||||
retObject.insert("uptime", uptime);
|
||||
|
||||
QString cputype = General::RunCommand("sysctl -n hw.model").simplified();
|
||||
retObject.insert("cputype", cputype);
|
||||
|
||||
QString cpucores = General::RunCommand("sysctl -n kern.smp.cpus").simplified();
|
||||
retObject.insert("cpucores", cpucores);
|
||||
|
||||
bool ok;
|
||||
QString tmp;
|
||||
QString totalmem = General::RunCommand("sysctl -n hw.realmem").simplified();
|
||||
totalmem.toLong(&ok);
|
||||
if ( ok ) {
|
||||
retObject.insert("totalmem", tmp.setNum(totalmem.toLong() / 1024 / 1024));
|
||||
}
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
//===========================================
|
||||
// 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 __PCBSD_LIB_UTILS_SYSINFO_H
|
||||
#define __PCBSD_LIB_UTILS_SYSINFO_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include "sysadm-global.h"
|
||||
|
||||
namespace sysadm{
|
||||
|
||||
class SysInfo{
|
||||
public:
|
||||
static QJsonObject batteryInfo();
|
||||
static QJsonObject cpuPercentage();
|
||||
static QJsonObject cpuTemps();
|
||||
static QJsonObject externalDevicePaths();
|
||||
static QJsonObject memoryStats();
|
||||
static QJsonObject systemInfo();
|
||||
};
|
||||
|
||||
} //end of pcbsd namespace
|
||||
|
||||
#endif
|
||||
@@ -1,151 +0,0 @@
|
||||
//===========================================
|
||||
// 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 <QUuid>
|
||||
#include "sysadm-general.h"
|
||||
#include "sysadm-update.h"
|
||||
#include "sysadm-global.h"
|
||||
|
||||
using namespace sysadm;
|
||||
|
||||
//PLEASE: Keep the functions in the same order as listed in pcbsd-general.h
|
||||
|
||||
// Return a list of updates available
|
||||
QJsonObject Update::checkUpdates() {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList output = General::RunCommand("pc-updatemanager check").split("\n");
|
||||
QString nameval;
|
||||
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("Your system is up to date!") != -1 )
|
||||
{
|
||||
retObject.insert("status", "noupdates");
|
||||
return retObject;
|
||||
}
|
||||
if ( output.at(i).indexOf("NAME: ") != -1 )
|
||||
nameval = output.at(i).section(" ", 1, 1);
|
||||
|
||||
if ( output.at(i).indexOf("TYPE: SECURITYUPDATE") != -1 ) {
|
||||
QJsonObject itemvals;
|
||||
itemvals.insert("name", nameval);
|
||||
retObject.insert("security", itemvals);
|
||||
}
|
||||
if ( output.at(i).indexOf("TYPE: SYSTEMUPDATE") != -1 ) {
|
||||
QJsonObject itemvals;
|
||||
itemvals.insert("name", nameval);
|
||||
if ( output.size() > ( i + 1) )
|
||||
itemvals.insert("tag", output.at(i+1).section(" ", 1, 1));
|
||||
if ( output.size() > ( i + 2) )
|
||||
itemvals.insert("version", output.at(i+2).section(" ", 1, 1));
|
||||
retObject.insert("majorupgrade", itemvals);
|
||||
}
|
||||
if ( output.at(i).indexOf("TYPE: PATCH") != -1 ) {
|
||||
QJsonObject itemvals;
|
||||
itemvals.insert("name", nameval);
|
||||
if ( output.size() > ( i + 1) )
|
||||
itemvals.insert("tag", output.at(i+1).section(" ", 1, 1));
|
||||
if ( output.size() > ( i + 2) )
|
||||
itemvals.insert("details", output.at(i+2).section(" ", 1, 1));
|
||||
if ( output.size() > ( i + 3) )
|
||||
itemvals.insert("date", output.at(i+3).section(" ", 1, 1));
|
||||
if ( output.size() > ( i + 4) )
|
||||
itemvals.insert("size", output.at(i+4).section(" ", 1, 1));
|
||||
retObject.insert("patch", itemvals);
|
||||
}
|
||||
if ( output.at(i).indexOf("TYPE: PKGUPDATE") != -1 ) {
|
||||
QJsonObject itemvals;
|
||||
itemvals.insert("name", nameval);
|
||||
retObject.insert("packageupdate", itemvals);
|
||||
}
|
||||
}
|
||||
|
||||
// Update status that we have updates
|
||||
retObject.insert("status", "updatesavailable");
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// List available branches we can switch to
|
||||
QJsonObject Update::listBranches() {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList output = General::RunCommand("pc-updatemanager branches").split("\n");
|
||||
|
||||
bool inSection = false;
|
||||
for ( int i = 0; i < output.size(); i++)
|
||||
{
|
||||
if ( output.at(i).indexOf("-----------------") != -1 ) {
|
||||
inSection = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!inSection)
|
||||
continue;
|
||||
|
||||
if ( output.at(i).isEmpty() )
|
||||
break;
|
||||
|
||||
QString tmp = output.at(i).section(" ", 0, 0);
|
||||
QString tmp2 = output.at(i).section(" ", 1, 1);
|
||||
if ( tmp2 == "*" )
|
||||
retObject.insert(tmp, "active");
|
||||
else
|
||||
retObject.insert(tmp, "available");
|
||||
}
|
||||
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Kickoff an update process
|
||||
QJsonObject Update::startUpdate(QJsonObject jsin) {
|
||||
QJsonObject retObject;
|
||||
|
||||
QStringList keys = jsin.keys();
|
||||
if (! keys.contains("target") ) {
|
||||
retObject.insert("error", "Missing required key 'target'");
|
||||
return retObject;
|
||||
}
|
||||
// Save the target
|
||||
QString target;
|
||||
target = jsin.value("target").toString();
|
||||
|
||||
QString flags;
|
||||
if ( target == "chbranch" ) {
|
||||
if (! keys.contains("branch") ) {
|
||||
retObject.insert("error", "Missing required key 'branch'");
|
||||
return retObject;
|
||||
}
|
||||
flags = "chbranch " + jsin.value("branch").toString();
|
||||
} else if ( target == "pkgupdate" ) {
|
||||
flags = "pkgupdate";
|
||||
} else if ( target == "fbsdupdate" ) {
|
||||
flags = "fbsdupdate";
|
||||
} else if ( target == "fbsdupdatepkgs" ) {
|
||||
flags = "fbsdupdatepkgs";
|
||||
} else if ( target == "standalone" ) {
|
||||
if (! keys.contains("tag") ) {
|
||||
retObject.insert("error", "Missing required key 'tag'");
|
||||
return retObject;
|
||||
}
|
||||
flags = "install " + jsin.value("tag").toString();
|
||||
} else {
|
||||
// Ruh-roh
|
||||
retObject.insert("error", "Unknown target key: " + target);
|
||||
return retObject;
|
||||
}
|
||||
|
||||
// Create a unique ID for this queued action
|
||||
QString ID = QUuid::createUuid().toString();
|
||||
|
||||
//DISPATCHER::queueProcess(ID, "pc-updatemanager " + flags).split("\n");
|
||||
|
||||
// Return some details to user that the action was queued
|
||||
retObject.insert("command", "pc-updatemanger " + flags);
|
||||
retObject.insert("comment", "Task Queued");
|
||||
retObject.insert("queueid", ID);
|
||||
return retObject;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
//===========================================
|
||||
// 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 __PCBSD_LIB_UTILS_UPDATER_H
|
||||
#define __PCBSD_LIB_UTILS_UPDATER_H
|
||||
|
||||
#include <QJsonObject>
|
||||
#include "sysadm-global.h"
|
||||
|
||||
namespace sysadm{
|
||||
|
||||
class Update{
|
||||
public:
|
||||
static QJsonObject checkUpdates();
|
||||
static QJsonObject listBranches();
|
||||
static QJsonObject startUpdate(QJsonObject);
|
||||
};
|
||||
|
||||
} //end of pcbsd namespace
|
||||
|
||||
#endif
|
||||
@@ -1,546 +0,0 @@
|
||||
//===========================================
|
||||
// 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 home, QString shell, int uid, int gid, bool encrypt)
|
||||
{
|
||||
User user;
|
||||
user.UserName = userName;
|
||||
user.FullName = fullName;
|
||||
user.HomeFolder = (home.isEmpty())?"/usr/home/"+userName : home;
|
||||
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
|
||||
if(!home.isEmpty())
|
||||
{
|
||||
args << "-d"; //set the home directory to
|
||||
args << home; //this
|
||||
}
|
||||
args << "-s"; //set the user's shell
|
||||
args << shell; //to this
|
||||
if(gid != -1)
|
||||
{
|
||||
args << "-g"; //set the group id to
|
||||
args << QString::number(gid); //this
|
||||
}
|
||||
if(uid != -1)
|
||||
{
|
||||
args << "-u"; //set the user id to
|
||||
args << QString::number(uid); //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);
|
||||
}
|
||||
|
||||
//if we're going to PersonaCrypt the home directory
|
||||
if(encrypt)
|
||||
initPCDevice(user,home,password);
|
||||
|
||||
//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)
|
||||
{
|
||||
//Don't Change the password of a user with an encrypted Home directory
|
||||
if( !QFile::exists("/var/db/personacrypt/"+user.UserName+".key") ){ return; }
|
||||
|
||||
//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();
|
||||
QStringList userStrings;
|
||||
QStringList args;
|
||||
if(!chroot.isEmpty())
|
||||
{
|
||||
args << chroot;
|
||||
args << "pw";
|
||||
}
|
||||
args << "usershow";
|
||||
args << "-a";
|
||||
if(chroot.isEmpty())
|
||||
userStrings = General::RunCommand("pw",args).split("\n");
|
||||
else
|
||||
userStrings = General::RunCommand("chroot",args).split("\n");
|
||||
|
||||
//remove the empty string at the end
|
||||
userStrings.removeLast();
|
||||
|
||||
for(QString line : userStrings)
|
||||
{
|
||||
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(":",8,8);
|
||||
user.Shell = line.section(":",9,9);
|
||||
user.FullName = line.section(":",7,7);
|
||||
|
||||
users.append(user);
|
||||
}
|
||||
}
|
||||
|
||||
void UserManager::loadGroups()
|
||||
{
|
||||
groups.clear();
|
||||
QStringList groupStrings;
|
||||
QStringList args;
|
||||
if(!chroot.isEmpty())
|
||||
{
|
||||
args << chroot;
|
||||
args << "pw";
|
||||
}
|
||||
args << "groupshow";
|
||||
args << "-a";
|
||||
if(chroot.isEmpty())
|
||||
groupStrings = General::RunCommand("pw",args).split("\n");
|
||||
else
|
||||
groupStrings = General::RunCommand("chroot",args).split("\n");
|
||||
|
||||
//remove the empty string at the end
|
||||
groupStrings.removeLast();
|
||||
|
||||
for(QString line : groupStrings)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
|
||||
void UserManager::importPCKey(User user, QString filename){
|
||||
//Double check that the key does not exist (button should have been hidden earlier if invalid)
|
||||
if( QFile::exists("/var/db/personacrypt/"+user.UserName+".key") ){ return; }
|
||||
|
||||
//if the location is empty cancel
|
||||
if(filename.isEmpty()){ return; }
|
||||
|
||||
//Now run the import command
|
||||
QStringList args;
|
||||
args << "import";
|
||||
args << "\""+filename + "\"";
|
||||
if( 0 == General::RunCommand("personacrypt",args) ){
|
||||
//Success
|
||||
qDebug("The key file was imported successfully.");
|
||||
}else{
|
||||
//Failure
|
||||
qWarning("The key file could not be imported. Please ensure you are using a valid file.");
|
||||
}
|
||||
}
|
||||
|
||||
void UserManager::exportPCKey(User user, QString filename){
|
||||
//Double check that the key exists (button should have been hidden earlier if invalid)
|
||||
if( !QFile::exists("/var/db/personacrypt/"+user.UserName+".key") ){ return; }
|
||||
|
||||
if(filename.isEmpty()){ return; } //cancelled
|
||||
if( !filename.endsWith(".key") ){ filename.append(".key"); }
|
||||
//Now get/save the key file
|
||||
QStringList args;
|
||||
args << "export";
|
||||
args << "\"" + user.UserName + "\"";
|
||||
QString key = General::RunCommand("personacrypt",args);
|
||||
|
||||
QFile file(filename);
|
||||
if( !file.open(QIODevice::WriteOnly | QIODevice::Truncate) ){
|
||||
//Could not open output file
|
||||
qWarning() <<"Output file could not be opened:\n\n" << filename;
|
||||
return;
|
||||
}
|
||||
QTextStream out(&file);
|
||||
out << key;
|
||||
file.close();
|
||||
qDebug() << "The PersonaCrypt key has been saved successfully: \n\n" << filename;
|
||||
}
|
||||
|
||||
void UserManager::disablePCKey(User user){
|
||||
//Double check that the key exists (button should have been hidden earlier if invalid)
|
||||
if( !QFile::exists("/var/db/personacrypt/"+user.UserName+".key") ){ return; }
|
||||
|
||||
if( QFile::remove("/var/db/personacrypt/"+user.UserName+".key") ){
|
||||
//Success
|
||||
qDebug("The PersonaCrypt user key has been disabled." );
|
||||
}else{
|
||||
//Failure (should almost never happen, since this utility runs as root and just needs to delete a file)
|
||||
qDebug("The PersonaCrypt user key could not be removed. Do you have the proper permissions?" );
|
||||
}
|
||||
}
|
||||
|
||||
void UserManager::disableAndCopyPCKey(User user, QString password){
|
||||
QStringList args;
|
||||
args << "list";
|
||||
QStringList cusers = General::RunCommand("personacrypt",args).split("\n");
|
||||
bool available = false;
|
||||
for(int i=0; i<cusers.length(); i++){
|
||||
if(cusers[i].section(" on ",0,0) == user.UserName){ available = true; break; } //disk is connected to the system
|
||||
}
|
||||
if(!available){
|
||||
//Warn the user that they need to plug in their USB stick first
|
||||
qWarning("PersonaCrypt Device Not Found, Please ensure that your PersonaCrypt device is connected to the system and try again.");
|
||||
return;
|
||||
}
|
||||
|
||||
if(password.isEmpty()){ return; } //cancelled
|
||||
//Save the password to a temporary file
|
||||
QTemporaryFile tmpfile("/tmp/.XXXXXXXXXXXXXXXXXXXX");
|
||||
if( !tmpfile.open() ){ return; } //could not create a temporary file (extremely rare)
|
||||
QTextStream out(&tmpfile);
|
||||
out << password;
|
||||
tmpfile.close();
|
||||
|
||||
//Now run the PersonaCrypt command
|
||||
args.clear();
|
||||
args << "remove";
|
||||
args << "\"" + user.UserName + "\"";
|
||||
args << "\"" + tmpfile.fileName() + "\"";
|
||||
if(0 == General::RunCommand("personacrypt",args) ){
|
||||
//Success
|
||||
qDebug("Success; The data for this user has been merged onto the system and the system key has been disabled");
|
||||
}else{
|
||||
//Failure
|
||||
qWarning("Failure; The PersonaCrypt user data could not be merged onto the system. Invalid Password?" );
|
||||
}
|
||||
}
|
||||
|
||||
void UserManager::initPCDevice(User user, QString home, QString password)
|
||||
{
|
||||
//Double check that the key does not exist (button should have been hidden earlier if invalid)
|
||||
if( QFile::exists("/var/db/personacrypt/" + user.UserName + ".key") ){ return; }
|
||||
|
||||
//Prompt for the user to select a device
|
||||
QStringList args;
|
||||
args << "list";
|
||||
args << "-r";
|
||||
QStringList devlist = General::RunCommand("personacrypt",args).split("\n");
|
||||
for(int i=0; i<devlist.length(); i++){
|
||||
//qDebug() << "Devlist:" << devlist[i];
|
||||
if(devlist[i].isEmpty() || devlist[i].startsWith("gpart:"))
|
||||
{
|
||||
devlist.removeAt(i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
if(devlist.isEmpty() || devlist.join("").simplified().isEmpty()){
|
||||
qWarning("No Devices Found; Please connect a removable device and try again");
|
||||
return;
|
||||
}
|
||||
|
||||
args.clear();
|
||||
args << "-h";
|
||||
args << user.HomeFolder;
|
||||
bool ok = false;
|
||||
QString space = General::RunCommand("df -h "+home).split("\n").filter(home).join("");
|
||||
space.replace("\t"," ");
|
||||
space = space.section(" ",2,2,QString::SectionSkipEmpty);
|
||||
|
||||
if(!ok || home.isEmpty()){ return; }
|
||||
|
||||
home = home.section(":",0,0); //only need the raw device
|
||||
//Save the password to a temporary file (for input to personacrypt)
|
||||
QTemporaryFile tmpfile("/tmp/.XXXXXXXXXXXXXXX");
|
||||
if(!tmpfile.open()){
|
||||
//Error: could not open a temporary file
|
||||
qWarning("Error; Could not create a temporary file for personacrypt");
|
||||
return;
|
||||
}
|
||||
QTextStream out(&tmpfile);
|
||||
out << password;
|
||||
tmpfile.close();
|
||||
//Now start the process of setting up the device
|
||||
bool success = false;
|
||||
args.clear();
|
||||
args << "init";
|
||||
args << "\""+user.UserName + "\"";
|
||||
args << "\"" + tmpfile.fileName() + "\"";
|
||||
args << home;
|
||||
QStringList output = General::RunCommand(success,"personacrypt",args).split("\n");
|
||||
if(success){
|
||||
//Success
|
||||
qDebug("Success; The PersonaCrypt device was successfully initialized");
|
||||
}else{
|
||||
//Failure - make sure the key was not created before the failure
|
||||
if(QFile::exists("/var/db/personacrypt/"+user.UserName+".key")){
|
||||
QFile::remove("/var/db/personacrypt/"+user.UserName+".key");
|
||||
}
|
||||
//Now show the error message with the log
|
||||
qWarning("Failure; The PersonaCrypt device could not be initialized");
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
//===========================================
|
||||
// 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;
|
||||
Encrypted = false;
|
||||
}
|
||||
|
||||
QString FullName;
|
||||
QString UserName;
|
||||
int ID;
|
||||
QString HomeFolder;
|
||||
QString Shell;
|
||||
int GroupID;
|
||||
bool Encrypted;
|
||||
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 home the location of the home directory
|
||||
* @param shell the user's shell, defaults to /bin/tcsh
|
||||
* @param uid the user id of the user
|
||||
* @param gid the group id of the user
|
||||
* @param encrypt whether to personaCrypt the User's home directory
|
||||
*/
|
||||
void NewUser(QString fullName, QString userName, QString password, QString home = "", QString shell = "/bin/tcsh", int uid = -1, int gid = -1, bool encrypt=false);
|
||||
/**
|
||||
* @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();
|
||||
|
||||
/**
|
||||
* @brief initPCDevice Initiate PersonaCrypt for the user
|
||||
* @param user the user to initiate PersonaCrypt for
|
||||
* @param home the location of the home directory
|
||||
* @param password the password of the user
|
||||
*/
|
||||
void initPCDevice(User user, QString home, QString password);
|
||||
|
||||
/**
|
||||
* @brief importPCKey Import a PersonaCrypt Key
|
||||
* @param user the user to import the key for
|
||||
* @param filename the location of the key
|
||||
*/
|
||||
void importPCKey(User user, QString filename);
|
||||
/**
|
||||
* @brief exportPCKey Export a PersonaCrypt Key
|
||||
* @param user the user to export the key for
|
||||
* @param filename the file to export to
|
||||
*/
|
||||
void exportPCKey(User user, QString filename);
|
||||
/**
|
||||
* @brief disablePCKey Disables a PersonaCrypt key
|
||||
* @param user the user to diable PersonaCrypt for
|
||||
*/
|
||||
void disablePCKey(User user);
|
||||
/**
|
||||
* @brief disableAndCopyPCKey Disable a PersonaCrypt Key
|
||||
* @param user for this user
|
||||
* @param password password for the PersonaCrypt
|
||||
*/
|
||||
void disableAndCopyPCKey(User user, QString password);
|
||||
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