1
0
mirror of https://github.com/altlinux/admc.git synced 2025-03-31 02:50:17 +03:00

implement gpt permission sync

add gpo_get_gpt_contents()
This commit is contained in:
Dmitry Degtyarev 2021-08-18 17:10:30 +04:00
parent 1d253ee33e
commit 63af5cc3b1
4 changed files with 146 additions and 98 deletions

View File

@ -1325,44 +1325,79 @@ bool AdInterface::create_gpo(const QString &display_name, QString &dn_out) {
return false;
}
//
// Set security descriptor for sysvol dir
//
const bool sync_perms_success = gpo_sync_perms(dn);
// First get descriptor of the GPO
const AdObject gpc_object = search_object(dn);
const QString gpt_sd_string = get_gpt_sd_string(&gpc_object, AceMaskFormat_Decimal);
if (gpt_sd_string.isEmpty()) {
d->error_message(tr("Failed to create GPO"), tr("Failed to generate GPT security descriptor"));
return false;
}
qDebug() << "gpt_sd_string:";
for (auto e : gpt_sd_string.split(",")) {
qDebug() << e;
}
// Set descriptor on all sysvol files that were created
const QList<QString> sysvol_list = {
main_dir,
machine_dir,
user_dir,
ini_file_path,
};
for (const QString &path : sysvol_list) {
const int set_sd_result = smbc_setxattr(cstr(path), "system.nt_sec_desc.*", cstr(gpt_sd_string), strlen(cstr(gpt_sd_string)), 0);
if (set_sd_result != 0) {
d->error_message(QString(tr("Failed to set permissions for GPT path \"%1\"")).arg(path), strerror(errno));
return false;
}
if (!sync_perms_success) {
// NOTE: don't fail if failed to sync perms, user
// can retry it later
}
return true;
}
QList<QString> AdInterfacePrivate::gpo_get_gpt_contents(const QString &gpt_root_path, bool *ok) {
// Collect all contents of the path into a list
QList<QString> explore_stack;
QList<QString> seen_stack;
explore_stack.append(gpt_root_path);
seen_stack.append(gpt_root_path);
while (!explore_stack.isEmpty()) {
const QString path = explore_stack.takeLast();
const int dirp = smbc_opendir(cstr(path));
if (dirp < 0) {
*ok = false;
qDebug() << "smbc_opendir() error";
return QList<QString>();
}
// NOTE: set errno to 0, so that we know
// when readdir() fails because it will
// change errno.
errno = 0;
smbc_dirent *child_dirent;
while ((child_dirent = smbc_readdir(dirp)) != NULL) {
const QString child_name = QString(child_dirent->name);
const bool is_dot_path = (child_name == "." || child_name == "..");
if (is_dot_path) {
continue;
} else {
const QString child_path = path + "/" + child_name;
seen_stack.append(child_path);
const bool child_is_dir = smb_path_is_dir(child_path, ok);
if (!*ok) {
return QList<QString>();
}
if (child_is_dir) {
explore_stack.append(child_path);
}
}
}
if (errno != 0) {
*ok = false;
qDebug() << "smbc_readdir() error" << path << strerror(errno);
return QList<QString>();
}
smbc_closedir(dirp);
}
return seen_stack;
}
bool AdInterface::delete_gpo(const QString &dn) {
// NOTE: try to execute both steps, even if first one
// (deleting gpc) fails
@ -1468,6 +1503,18 @@ bool AdInterface::check_gpo_perms(const QString &gpo) {
return out;
}();
qDebug() << "--------";
qDebug() << "gpc_sd:";
for (auto e : QString(gpc_sd).split(",")) {
qDebug() << e;
}
qDebug() << "--------";
qDebug() << "gpt_sd:";
for (auto e : QString(gpt_sd).split(",")) {
qDebug() << e;
}
if (gpc_sd.isEmpty() || gpt_sd.isEmpty()) {
return false;
}
@ -1477,6 +1524,50 @@ bool AdInterface::check_gpo_perms(const QString &gpo) {
return sd_match;
}
bool AdInterface::gpo_sync_perms(const QString &dn) {
// First get GPC descriptor
const AdObject gpc_object = search_object(dn);
const QString name = gpc_object.get_string(ATTRIBUTE_DISPLAY_NAME);
const QString gpt_sd_string = get_gpt_sd_string(&gpc_object, AceMaskFormat_Decimal);
const QString error_context = QString(tr("Failed to sync permissions of GPO \"%1\"")).arg(name);
if (gpt_sd_string.isEmpty()) {
d->error_message(error_context, tr("Failed to generate GPT security descriptor"));
return false;
}
// Get list of GPT contents
// NOTE: order is important, have to set perms of parent
// folders before their contents, otherwise fails to
// set! Default gpo_get_gpt_contents() order is good.
const QString filesys_path = gpc_object.get_string(ATTRIBUTE_GPC_FILE_SYS_PATH);
const QString smb_path = sysvol_path_to_smb(filesys_path);
bool ok = true;
const QList<QString> path_list = d->gpo_get_gpt_contents(smb_path, &ok);
if (!ok || path_list.isEmpty()) {
d->error_message(error_context, QString(tr("Failed to read GPT contents of \"%1\"")).arg(smb_path));
return false;
}
// Set descriptor on all GPT contents
for (const QString &path : path_list) {
const int set_sd_result = smbc_setxattr(cstr(path), "system.nt_sec_desc.*", cstr(gpt_sd_string), strlen(cstr(gpt_sd_string)), 0);
if (set_sd_result != 0) {
const QString error = QString(tr("Failed to set permissions, %1")).arg(strerror(errno));
d->error_message(error_context, error);
return false;
}
}
d->success_message(QString(tr("Synced permissions of GPO \"%1\".")).arg(name));
return true;
}
void AdInterfacePrivate::success_message(const QString &msg, const DoStatusMsg do_msg) {
if (do_msg == DoStatusMsg_No) {
return;
@ -1535,72 +1626,16 @@ int AdInterfacePrivate::get_ldap_result() const {
bool AdInterfacePrivate::delete_gpt(const QString &parent_path) {
bool ok = true;
// Collect all contents of the path into a list
const QList<QString> path_list = [&]() {
QList<QString> explore_stack;
QList<QString> seen_stack;
explore_stack.append(parent_path);
while (!explore_stack.isEmpty()) {
const QString path = explore_stack.takeLast();
const int dirp = smbc_opendir(cstr(path));
if (dirp < 0) {
ok = false;
return QList<QString>();
}
// NOTE: set errno to 0, so that we know
// when readdir() fails because it will
// change errno.
errno = 0;
smbc_dirent *child_dirent;
while ((child_dirent = smbc_readdir(dirp)) != NULL) {
const QString child_name = QString(child_dirent->name);
const bool is_dot_path = (child_name == "." || child_name == "..");
if (is_dot_path) {
continue;
} else {
const QString child_path = path + "/" + child_name;
const bool child_is_dir = smb_path_is_dir(child_path, &ok);
if (!ok) {
return QList<QString>();
}
if (child_is_dir) {
explore_stack.append(child_path);
}
}
}
if (errno != 0) {
ok = false;
error_message(QString(tr("Failed to read contents of folder %1")).arg(path), strerror(errno));
qDebug() << "smbc_readdir() error" << path << strerror(errno);
return QList<QString>();
}
smbc_closedir(dirp);
}
// Reverse so that deepest files are first in order
std::reverse(seen_stack.begin(), seen_stack.end());
return seen_stack;
}();
QList<QString> path_list = gpo_get_gpt_contents(parent_path, &ok);
if (!ok) {
return false;
}
// NOTE: have to reverse so deepest paths are first to
// delete correctly
std::reverse(path_list.begin(), path_list.end());
for (const QString &path : path_list) {
const bool is_dir = smb_path_is_dir(path, &ok);
if (!ok) {

View File

@ -171,6 +171,7 @@ public:
QString sysvol_path_to_smb(const QString &sysvol_path) const;
bool check_gpo_perms(const QString &gpo);
bool gpo_sync_perms(const QString &gpo);
private:
AdInterfacePrivate *d;

View File

@ -59,6 +59,10 @@ public:
bool connect_via_ldap(const char *uri);
bool delete_gpt(const QString &parent_path);
bool smb_path_is_dir(const QString &path, bool *ok);
// Returns GPT contents including the root path, in
// order of increasing depth, so root path is first
QList<QString> gpo_get_gpt_contents(const QString &gpt_root_path, bool *ok);
};
#endif /* AD_INTERFACE_P_H */

View File

@ -135,6 +135,8 @@ void PolicyResultsWidget::update(const QModelIndex &index) {
}
void PolicyResultsWidget::update(const QString &new_gpo) {
gpo = new_gpo;
AdInterface ad;
if (ad_failed(ad)) {
return;
@ -153,19 +155,25 @@ void PolicyResultsWidget::update(const QString &new_gpo) {
const QMessageBox::StandardButtons buttons = (QMessageBox::Yes | QMessageBox::No);
auto message_box = new QMessageBox(icon, title, text, buttons, this);
message_box->open();
connect(
message_box, &QDialog::accepted,
[&]() {
// TODO: update perms
[this]() {
AdInterface ad_inner;
if (ad_failed(ad_inner)) {
return;
}
ad_inner.gpo_sync_perms(gpo);
g_status()->display_ad_messages(ad_inner, this);
});
message_box->open();
}
model->removeRows(0, model->rowCount());
gpo = new_gpo;
const QString base = g_adconfig->domain_head();
const SearchScope scope = SearchScope_All;
const QList<QString> attributes = {ATTRIBUTE_NAME, ATTRIBUTE_GPLINK};