1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216
|
/*
* Copyright (C) 2019 ~ 2021 Uniontech Software Technology Co.,Ltd.
*
* Author: linxun <linxun@uniontech.com>
*
* Maintainer: linxun <linxun@uniontech.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "logviewerservice.h"
#include <QCoreApplication>
#include <QDebug>
#include <QStringList>
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusConnectionInterface>
const QStringList ValidInvokerExePathList1 = {"/usr/bin/deepin-log-viewer"};
LogViewerService::LogViewerService(QObject *parent)
: QObject(parent)
{
m_commands.insert("dmesg", "dmesg -r");
m_commands.insert("last", "last -x");
m_commands.insert("journalctl_system", "journalctl -r");
m_commands.insert("journalctl_boot", "journalctl -b -r");
}
/*!
* \~chinese \brief LogViewerService::readLog 读取日志文件
* \~chinese \param filePath 文件路径
* \~chinese \return 读取的日志
*/
QString LogViewerService::readLog(const QString &filePath)
{
//增加服务黑名单,只允许通过提权接口读取/var/log下,家目录下和临时目录下的文件
if ((!filePath.startsWith("/var/log/") && !filePath.startsWith("/tmp") && !filePath.startsWith("/home")) || filePath.contains("..") || !isValidInvoker()) {
return " ";
}
m_process.start("cat", QStringList() << filePath);
m_process.waitForFinished(-1);
QByteArray byte = m_process.readAllStandardOutput();
//QByteArray -> QString 如果遇到0x00,会导致转换终止
//replace("\x00", "")和replace("\u0000", "")无效
for(int i = 0;i != byte.size();++i) {
if(byte.at(i) == 0x00) {
byte.remove(i, 1);
i--;
}
}
return QString::fromUtf8(byte);
}
/*!
* \~chinese \brief LogViewerService::exitCode 返回进程状态
* \~chinese \return 进程返回值
*/
int LogViewerService::exitCode()
{
return m_process.exitCode();
}
/*!
* \~chinese \brief LogViewerService::quit 退出服务端程序
*/
void LogViewerService::quit()
{
qDebug() << "LogViewService::Quit called";
QCoreApplication::exit(0);
}
/*!
* \~chinese \brief LogViewerService::getFileInfo 获取想到读取日志文件的路径
* \~chinese \param file 日志文件的类型
* \~chinese \return 所有日志文件路径列表
*/
QStringList LogViewerService::getFileInfo(const QString &file, bool unzip)
{
int fileNum = 0;
if (tmpDir.isValid()) {
tmpDirPath = tmpDir.path();
}
QStringList fileNamePath;
QString nameFilter;
QDir dir;
if (file.contains("deepin", Qt::CaseInsensitive) || file.contains("uos", Qt::CaseInsensitive)) {
QFileInfo appFileInfo(file);
if (!appFileInfo.isFile()) {
return QStringList() << "";
}
QString appDir = appFileInfo.absolutePath();
nameFilter = appDir.mid(appDir.lastIndexOf("/") + 1, appDir.size() - 1);
dir.setPath(appDir);
} else {
dir.setPath("/var/log");
nameFilter = file;
}
//要判断路径是否存在
if (!dir.exists()) {
qWarning() << "it is not true path";
return QStringList() << "";
}
dir.setFilter(QDir::Files | QDir::NoSymLinks); //实现对文件的过滤
dir.setNameFilters(QStringList() << nameFilter + ".*"); //设置过滤
dir.setSorting(QDir::Time);
QFileInfoList fileList = dir.entryInfoList();
for (int i = 0; i < fileList.count(); i++) {
if (QString::compare(fileList[i].suffix(), "gz", Qt::CaseInsensitive) != 0) {
fileNamePath.append(fileList[i].absoluteFilePath());
} else if (unzip) {
// qDebug() << tmpDirPath;
QProcess m_process;
QString command = "gunzip";
QStringList args;
args.append("-c");
// qDebug() << fileList[i].absoluteFilePath();
args.append(fileList[i].absoluteFilePath());
m_process.setStandardOutputFile(tmpDirPath + "/" + QString::number(fileNum) + ".txt");
m_process.start(command, args);
m_process.waitForFinished(-1);
// qDebug() << m_process.readAll();
fileNamePath.append(tmpDirPath + "/" + QString::number(fileNum) + ".txt");
fileNum++;
}
}
// qInfo()<<fileNamePath.count()<<fileNamePath<<"******************************";
return fileNamePath;
}
bool LogViewerService::exportLog(const QString &outDir, const QString &in, bool isFile)
{
if (outDir.isEmpty() || in.isEmpty()) {
return false;
}
QString outFullPath = "";
QStringList arg = {"-c", ""};
if (isFile) {
//增加服务黑名单,只允许通过提权接口读取/var/log下,家目录下和临时目录下的文件
if ((!in.startsWith("/var/log/") && !in.startsWith("/tmp") && !in.startsWith("/home")) || in.contains("..")) {
return false;
}
QFileInfo filein(in);
if (!filein.isFile()) {
qInfo() << "in not file:" << in;
return false;
}
outFullPath = outDir + filein.fileName();
//复制文件
arg[1].append(QString("cp %1 %2;").arg(in, outDir));
} else {
auto it = m_commands.find(in);
if (it == m_commands.end()) {
qInfo() << "unknown command:" << in;
return false;
}
outFullPath = outDir + in + ".txt";
//结果重定向到文件
arg[1].append(QString("%1 >& %2;").arg(it.value(), outFullPath));
}
//设置文件权限
arg[1].append(QString("chmod 777 %1;").arg(outFullPath));
QProcess process;
process.start("/bin/bash", arg);
if (!process.waitForFinished()) {
qInfo() << "command error:" << arg;
return false;
}
return true;
}
bool LogViewerService::isValidInvoker()
{
bool valid = false;
QDBusConnection conn = connection();
QDBusMessage msg = message();
//判断是否存在执行路径
uint pid = conn.interface()->servicePid(msg.service()).value();
QFileInfo f(QString("/proc/%1/exe").arg(pid));
if (!f.exists()) {
valid = false;
} else {
valid = true;
}
//是否存在于可调用者名单中
QString invokerPath = f.canonicalFilePath();
if (valid)
valid = ValidInvokerExePathList1.contains(invokerPath);
//非法调用
if (!valid) {
sendErrorReply(QDBusError::ErrorType::Failed,
QString("(pid: %1)[%2] is not allowed to configrate firewall")
.arg(pid)
.arg((invokerPath)));
return false;
}
return true;
}
|