From 5b21f03d504759e1c885df4ff6b016ce17c0d6b7 Mon Sep 17 00:00:00 2001 From: Dmitry Degtyarev Date: Wed, 7 Apr 2021 15:01:56 +0400 Subject: [PATCH 1/7] add samba sources needed for work with security descriptors --- src/adldap/CMakeLists.txt | 9 + src/adldap/samba/dom_sid.c | 122 ++++++++ src/adldap/samba/dom_sid.h | 46 +++ src/adldap/samba/gp_manage.cpp | 269 ++++++++++++++++ src/adldap/samba/gp_manage.h | 38 +++ src/adldap/samba/ndr_security.c | 525 ++++++++++++++++++++++++++++++++ src/adldap/samba/ndr_security.h | 44 +++ src/adldap/samba/replace.c | 54 ++++ src/adldap/samba/replace.h | 71 +++++ 9 files changed, 1178 insertions(+) create mode 100644 src/adldap/samba/dom_sid.c create mode 100644 src/adldap/samba/dom_sid.h create mode 100644 src/adldap/samba/gp_manage.cpp create mode 100644 src/adldap/samba/gp_manage.h create mode 100644 src/adldap/samba/ndr_security.c create mode 100644 src/adldap/samba/ndr_security.h create mode 100644 src/adldap/samba/replace.c create mode 100644 src/adldap/samba/replace.h diff --git a/src/adldap/CMakeLists.txt b/src/adldap/CMakeLists.txt index 69ccfe2d..dee57172 100644 --- a/src/adldap/CMakeLists.txt +++ b/src/adldap/CMakeLists.txt @@ -10,6 +10,9 @@ find_package(Krb5 REQUIRED) find_package(Ldap REQUIRED) find_package(Resolv REQUIRED) +find_package(PkgConfig REQUIRED) +pkg_check_modules(NdrStandard REQUIRED IMPORTED_TARGET ndr_standard) + set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) @@ -21,6 +24,11 @@ add_library(adldap SHARED ad_display.cpp ad_filter.cpp + samba/gp_manage.cpp + samba/ndr_security.c + samba/dom_sid.c + samba/replace.c + adldap.qrc ) @@ -35,6 +43,7 @@ target_link_libraries(adldap Krb5::Krb5 Ldap::Ldap Resolv::Resolv + PkgConfig::NdrStandard ) set(TS_FILES diff --git a/src/adldap/samba/dom_sid.c b/src/adldap/samba/dom_sid.c new file mode 100644 index 00000000..99c2ea82 --- /dev/null +++ b/src/adldap/samba/dom_sid.c @@ -0,0 +1,122 @@ +/* + Unix SMB/CIFS implementation. + Samba utility functions + + Copyright (C) Stefan (metze) Metzmacher 2002-2004 + Copyright (C) Andrew Tridgell 1992-2004 + Copyright (C) Jeremy Allison 1999 + + 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 + (at your option) 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 . +*/ + +/* + * This file is a copy of private samba sources. Parts of it + * were removed or edited. + */ + +#include "dom_sid.h" + +#include "replace.h" + +/* + Convert a dom_sid to a string, printing into a buffer. Return the + string length. If it overflows, return the string length that would + result (buflen needs to be +1 for the terminating 0). +*/ +static int dom_sid_string_buf(const struct dom_sid *sid, char *buf, int buflen) +{ + int i, ofs, ret; + uint64_t ia; + + if (!sid) { + return strlcpy(buf, "(NULL SID)", buflen); + } + + ia = ((uint64_t)sid->id_auth[5]) + + ((uint64_t)sid->id_auth[4] << 8 ) + + ((uint64_t)sid->id_auth[3] << 16) + + ((uint64_t)sid->id_auth[2] << 24) + + ((uint64_t)sid->id_auth[1] << 32) + + ((uint64_t)sid->id_auth[0] << 40); + + ret = snprintf(buf, buflen, "S-%"PRIu8"-", sid->sid_rev_num); + if (ret < 0) { + return ret; + } + ofs = ret; + + if (ia >= UINT32_MAX) { + ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "0x%"PRIx64, ia); + } else { + ret = snprintf(buf+ofs, MAX(buflen-ofs, 0), "%"PRIu64, ia); + } + if (ret < 0) { + return ret; + } + ofs += ret; + + for (i = 0; i < sid->num_auths; i++) { + ret = snprintf( + buf+ofs, + MAX(buflen-ofs, 0), + "-%"PRIu32, + sid->sub_auths[i]); + if (ret < 0) { + return ret; + } + ofs += ret; + } + return ofs; +} + +/* + convert a dom_sid to a string +*/ +char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid) +{ + char buf[DOM_SID_STR_BUFLEN]; + char *result; + int len; + + len = dom_sid_string_buf(sid, buf, sizeof(buf)); + + if ((len < 0) || (len+1 > sizeof(buf))) { + return talloc_strdup(mem_ctx, "(SID ERR)"); + } + + /* + * Avoid calling strlen (via talloc_strdup), we already have + * the length + */ + result = (char *)talloc_memdup(mem_ctx, buf, len+1); + if (result == NULL) { + return NULL; + } + + /* + * beautify the talloc_report output + */ + talloc_set_name_const(result, result); + return result; +} + +char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst) +{ + int ret; + ret = dom_sid_string_buf(sid, dst->buf, sizeof(dst->buf)); + if ((ret < 0) || (ret >= sizeof(dst->buf))) { + strlcpy(dst->buf, "(INVALID SID)", sizeof(dst->buf)); + } + return dst->buf; +} diff --git a/src/adldap/samba/dom_sid.h b/src/adldap/samba/dom_sid.h new file mode 100644 index 00000000..689c376c --- /dev/null +++ b/src/adldap/samba/dom_sid.h @@ -0,0 +1,46 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Wilco Baan Hofman 2010 + * + * 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 + * (at your option) 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 . + */ + +/* + * This file is a copy of private samba sources. Parts of it + * were removed or edited. + */ + +#ifndef DOM_SID_H +#define DOM_SID_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include +#include + +#define DOM_SID_STR_BUFLEN (15*11+25) +char *dom_sid_string(TALLOC_CTX *mem_ctx, const struct dom_sid *sid); + +struct dom_sid_buf { char buf[DOM_SID_STR_BUFLEN]; }; +char *dom_sid_str_buf(const struct dom_sid *sid, struct dom_sid_buf *dst); + +#ifdef __cplusplus +} +#endif + +#endif /* DOM_SID_H */ diff --git a/src/adldap/samba/gp_manage.cpp b/src/adldap/samba/gp_manage.cpp new file mode 100644 index 00000000..fd83825e --- /dev/null +++ b/src/adldap/samba/gp_manage.cpp @@ -0,0 +1,269 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Wilco Baan Hofman 2010 + * + * 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 + * (at your option) 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 . + */ + +/* + * This file is a copy of private files from samba source. + * Parts of it were removed or edited. + */ + +#include "gp_manage.h" + +#include "dom_sid.h" + +#include + +/* + * This file is a copy of private samba sources. Parts of it + * were removed or edited. + */ + +bool security_descriptor_acl_add(struct security_descriptor *sd, + bool add_to_sacl, + const struct security_ace *ace) +{ + struct security_acl *acl = NULL; + + if (add_to_sacl) { + acl = sd->sacl; + } else { + acl = sd->dacl; + } + + if (acl == NULL) { + acl = talloc(sd, struct security_acl); + if (acl == NULL) { + // return NT_STATUS_NO_MEMORY; + return false; + } + acl->revision = SECURITY_ACL_REVISION_NT4; + acl->size = 0; + acl->num_aces = 0; + acl->aces = NULL; + } + + acl->aces = talloc_realloc(acl, acl->aces, + struct security_ace, acl->num_aces+1); + if (acl->aces == NULL) { + // return NT_STATUS_NO_MEMORY; + return false; + } + + acl->aces[acl->num_aces] = *ace; + + switch (acl->aces[acl->num_aces].type) { + case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: + case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: + case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT: + case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT: + acl->revision = SECURITY_ACL_REVISION_ADS; + break; + default: + break; + } + + acl->num_aces++; + + if (add_to_sacl) { + sd->sacl = acl; + sd->type |= SEC_DESC_SACL_PRESENT; + } else { + sd->dacl = acl; + sd->type |= SEC_DESC_DACL_PRESENT; + } + + // return NT_STATUS_OK; + return true; +} + +/* + add an ACE to the SACL of a security_descriptor +*/ + +bool security_descriptor_sacl_add(struct security_descriptor *sd, + const struct security_ace *ace) +{ + return security_descriptor_acl_add(sd, true, ace); +} + +/* + add an ACE to the DACL of a security_descriptor +*/ + +bool security_descriptor_dacl_add(struct security_descriptor *sd, + const struct security_ace *ace) +{ + return security_descriptor_acl_add(sd, false, ace); +} + +uint32_t gp_ads_to_dir_access_mask(uint32_t access_mask) +{ + uint32_t fs_mask; + + /* Copy the standard access mask */ + fs_mask = access_mask & 0x001F0000; + + /* When READ_PROP and LIST_CONTENTS are set, read access is granted on the GPT */ + if (access_mask & SEC_ADS_READ_PROP && access_mask & SEC_ADS_LIST) { + fs_mask |= SEC_STD_SYNCHRONIZE | SEC_DIR_LIST | SEC_DIR_READ_ATTRIBUTE | + SEC_DIR_READ_EA | SEC_DIR_TRAVERSE; + } + + /* When WRITE_PROP is set, full write access is granted on the GPT */ + if (access_mask & SEC_ADS_WRITE_PROP) { + fs_mask |= SEC_STD_SYNCHRONIZE | SEC_DIR_WRITE_ATTRIBUTE | + SEC_DIR_WRITE_EA | SEC_DIR_ADD_FILE | + SEC_DIR_ADD_SUBDIR; + } + + /* Map CREATE_CHILD to add file and add subdir */ + if (access_mask & SEC_ADS_CREATE_CHILD) + fs_mask |= SEC_DIR_ADD_FILE | SEC_DIR_ADD_SUBDIR; + + /* Map ADS delete child to dir delete child */ + if (access_mask & SEC_ADS_DELETE_CHILD) + fs_mask |= SEC_DIR_DELETE_CHILD; + + return fs_mask; +} + +struct security_acl *security_acl_dup(TALLOC_CTX *mem_ctx, + const struct security_acl *oacl) +{ + struct security_acl *nacl; + + if (oacl == NULL) { + return NULL; + } + + if (oacl->aces == NULL && oacl->num_aces > 0) { + return NULL; + } + + nacl = talloc (mem_ctx, struct security_acl); + if (nacl == NULL) { + return NULL; + } + + *nacl = (struct security_acl) { + .revision = oacl->revision, + .size = oacl->size, + .num_aces = oacl->num_aces, + }; + if (nacl->num_aces == 0) { + return nacl; + } + + nacl->aces = (struct security_ace *)talloc_memdup (nacl, oacl->aces, sizeof(struct security_ace) * oacl->num_aces); + if (nacl->aces == NULL) { + goto failed; + } + + return nacl; + + failed: + talloc_free (nacl); + return NULL; + +} + +bool gp_create_gpt_security_descriptor(TALLOC_CTX *mem_ctx, struct security_descriptor *ds_sd, struct security_descriptor **ret) { + struct security_descriptor *fs_sd; +// uint32_t i; + + /* Allocate the file system security descriptor */ + fs_sd = talloc(mem_ctx, struct security_descriptor); + // NT_STATUS_HAVE_NO_MEMORY(fs_sd); + + /* Copy the basic information from the directory server security descriptor */ + fs_sd->owner_sid = (dom_sid *) talloc_memdup(fs_sd, ds_sd->owner_sid, sizeof(struct dom_sid)); + if (fs_sd->owner_sid == NULL) { + TALLOC_FREE(fs_sd); + // return NT_STATUS_NO_MEMORY; + return false; + } + + fs_sd->group_sid = (dom_sid *) talloc_memdup(fs_sd, ds_sd->group_sid, sizeof(struct dom_sid)); + if (fs_sd->group_sid == NULL) { + TALLOC_FREE(fs_sd); + // return NT_STATUS_NO_MEMORY; + return false; + } + + fs_sd->type = ds_sd->type; + fs_sd->revision = ds_sd->revision; + + /* Copy the sacl */ + fs_sd->sacl = security_acl_dup(fs_sd, ds_sd->sacl); + if (fs_sd->sacl == NULL) { + TALLOC_FREE(fs_sd); + // return NT_STATUS_NO_MEMORY; + return false; + } + + /* Copy the dacl */ + fs_sd->dacl = talloc_zero(fs_sd, struct security_acl); + if (fs_sd->dacl == NULL) { + TALLOC_FREE(fs_sd); + // return NT_STATUS_NO_MEMORY; + return false; + } + + for (uint32_t i = 0; i < ds_sd->dacl->num_aces; i++) { + const char *trustee = dom_sid_string(fs_sd, &ds_sd->dacl->aces[i].trustee); + struct security_ace *ace; + + /* Don't add the allow for SID_BUILTIN_PREW2K */ + if (!(ds_sd->dacl->aces[i].type & SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT) && strcmp(trustee, SID_BUILTIN_PREW2K) == 0) { + talloc_free((void *) trustee); + continue; + } + + /* Copy the ace from the directory server security descriptor */ + ace = (security_ace *) talloc_memdup(fs_sd, &ds_sd->dacl->aces[i], sizeof(struct security_ace)); + if (ace == NULL) { + TALLOC_FREE(fs_sd); + // return NT_STATUS_NO_MEMORY; + return false; + } + + /* Set specific inheritance flags for within the GPO */ + ace->flags |= SEC_ACE_FLAG_OBJECT_INHERIT | SEC_ACE_FLAG_CONTAINER_INHERIT; + if (strcmp(trustee, SID_CREATOR_OWNER) == 0) { + ace->flags |= SEC_ACE_FLAG_INHERIT_ONLY; + } + + /* Get a directory access mask from the assigned access mask on the LDAP object */ + ace->access_mask = gp_ads_to_dir_access_mask(ace->access_mask); + + /* Add the ace to the security descriptor DACL */ + const bool dacl_add_success = security_descriptor_dacl_add(fs_sd, ace); + if (!dacl_add_success) { + // if (!NT_STATUS_IS_OK(status)) { + // DEBUG(0, ("Failed to add a dacl to file system security descriptor\n")); + // return status; + return false; + } + + /* Clean up the allocated data in this iteration */ + talloc_free((void *) trustee); + } + + *ret = fs_sd; + return true; +} diff --git a/src/adldap/samba/gp_manage.h b/src/adldap/samba/gp_manage.h new file mode 100644 index 00000000..774d5e5b --- /dev/null +++ b/src/adldap/samba/gp_manage.h @@ -0,0 +1,38 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Wilco Baan Hofman 2010 + * + * 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 + * (at your option) 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 . + */ + +/* + * This file is a copy of private samba sources. Parts of it + * were removed or edited. + */ + +#ifndef GP_MANAGE_H +#define GP_MANAGE_H + +extern "C" { + +#include +#include +#include + +}; + +bool gp_create_gpt_security_descriptor(TALLOC_CTX *mem_ctx, struct security_descriptor *ds_sd, struct security_descriptor **ret); + +#endif /* GP_MANAGE_H */ diff --git a/src/adldap/samba/ndr_security.c b/src/adldap/samba/ndr_security.c new file mode 100644 index 00000000..48449a10 --- /dev/null +++ b/src/adldap/samba/ndr_security.c @@ -0,0 +1,525 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Wilco Baan Hofman 2010 + * + * 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 + * (at your option) 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 . + */ + +/* + * This file is a copy of private samba sources. Parts of it + * were removed or edited. + */ + +// #include "util/util.h" +#include +#include +#include + +#ifndef N_ELEMENTS +#define N_ELEMENTS(arr) (sizeof(arr) / sizeof(arr[0])) +#endif + +// TODO: figure out how to define this +#define SMB_HAS_NEW_NDR_PULL_STEAL_SWITCH + +static enum ndr_err_code +ndr_pull_GUID(struct ndr_pull *ndr, + int ndr_flags, + struct GUID *r) +{ + uint32_t size_clock_seq_0 = 0; + uint32_t size_node_0 = 0; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->time_low)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->time_mid)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->time_hi_and_version)); + size_clock_seq_0 = 2; + NDR_CHECK(ndr_pull_array_uint8(ndr, + NDR_SCALARS, + r->clock_seq, + size_clock_seq_0)); + size_node_0 = 6; + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->node, size_node_0)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + } + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code +ndr_pull_security_ace_flags(struct ndr_pull *ndr, + int ndr_flags, + uint8_t *r) +{ + uint8_t v; + NDR_CHECK(ndr_pull_uint8(ndr, ndr_flags, &v)); + *r = v; + return NDR_ERR_SUCCESS; +} + + +static enum ndr_err_code +ndr_pull_security_ace_type(struct ndr_pull *ndr, + int ndr_flags, + enum security_ace_type *r) +{ + uint8_t v; + NDR_CHECK(ndr_pull_enum_uint8(ndr, ndr_flags, &v)); + *r = v; + return NDR_ERR_SUCCESS; +} + + +static enum ndr_err_code +ndr_pull_security_ace_object_flags(struct ndr_pull *ndr, + int ndr_flags, + uint32_t *r) +{ + uint32_t v; + NDR_CHECK(ndr_pull_uint32(ndr, ndr_flags, &v)); + *r = v; + return NDR_ERR_SUCCESS; +} + + +static enum ndr_err_code +ndr_pull_security_ace_object_type(struct ndr_pull *ndr, + int ndr_flags, + union security_ace_object_type *r) +{ + uint32_t level; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + /* This token is not used again (except perhaps below in the NDR_BUFFERS case) */ +#ifdef SMB_HAS_NEW_NDR_PULL_STEAL_SWITCH + NDR_CHECK(ndr_pull_steal_switch_value(ndr, r, &level)); +#else + level = ndr_pull_steal_switch_value(ndr, r); +#endif + NDR_CHECK(ndr_pull_union_align(ndr, 4)); + switch (level) { + case SEC_ACE_OBJECT_TYPE_PRESENT: { + NDR_CHECK(ndr_pull_GUID(ndr, NDR_SCALARS, &r->type)); + break; } + default: { + break; } + } + } + return NDR_ERR_SUCCESS; +} + + +static enum ndr_err_code +ndr_pull_security_ace_object_inherited_type(struct ndr_pull *ndr, + int ndr_flags, + union security_ace_object_inherited_type *r) +{ + uint32_t level; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + /* This token is not used again (except perhaps below in the NDR_BUFFERS case) */ +#ifdef SMB_HAS_NEW_NDR_PULL_STEAL_SWITCH + NDR_CHECK(ndr_pull_steal_switch_value(ndr, r, &level)); +#else + level = ndr_pull_steal_switch_value(ndr, r); +#endif + NDR_CHECK(ndr_pull_union_align(ndr, 4)); + switch (level) { + case SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT: { + NDR_CHECK(ndr_pull_GUID(ndr, + NDR_SCALARS, + &r->inherited_type)); + break; } + default: { + break; } + } + } + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code +ndr_pull_security_ace_object(struct ndr_pull *ndr, + int ndr_flags, + struct security_ace_object *r) +{ + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_security_ace_object_flags + (ndr, NDR_SCALARS, &r->flags)); + NDR_CHECK(ndr_pull_set_switch_value + (ndr, &r->type, r->flags & SEC_ACE_OBJECT_TYPE_PRESENT)); + NDR_CHECK(ndr_pull_security_ace_object_type + (ndr, NDR_SCALARS, &r->type)); + NDR_CHECK(ndr_pull_set_switch_value + (ndr, + &r->inherited_type, + r->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)); + NDR_CHECK(ndr_pull_security_ace_object_inherited_type + (ndr, NDR_SCALARS, &r->inherited_type)); + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_pull_set_switch_value + (ndr, + &r->type, + r->flags & SEC_ACE_OBJECT_TYPE_PRESENT)); + NDR_CHECK(ndr_pull_security_ace_object_type + (ndr, NDR_BUFFERS, &r->type)); + NDR_CHECK(ndr_pull_set_switch_value + (ndr, + &r->inherited_type, + r->flags & SEC_ACE_INHERITED_OBJECT_TYPE_PRESENT)); + NDR_CHECK(ndr_pull_security_ace_object_inherited_type + (ndr, NDR_BUFFERS, &r->inherited_type)); + } + return NDR_ERR_SUCCESS; +} + + +static enum ndr_err_code +ndr_pull_security_ace_object_ctr(struct ndr_pull *ndr, + int ndr_flags, + union security_ace_object_ctr *r) +{ + uint32_t level; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + /* This token is not used again (except perhaps below in the NDR_BUFFERS case) */ +#ifdef SMB_HAS_NEW_NDR_PULL_STEAL_SWITCH + NDR_CHECK(ndr_pull_steal_switch_value(ndr, r, &level)); +#else + level = ndr_pull_steal_switch_value(ndr, r); +#endif + NDR_CHECK(ndr_pull_union_align(ndr, 4)); + switch (level) { + case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: { + NDR_CHECK(ndr_pull_security_ace_object + (ndr, NDR_SCALARS, &r->object)); + break; } + case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: { + NDR_CHECK(ndr_pull_security_ace_object + (ndr, NDR_SCALARS, &r->object)); + break; } + case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT: { + NDR_CHECK(ndr_pull_security_ace_object + (ndr, NDR_SCALARS, &r->object)); + break; } + case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT: { + NDR_CHECK(ndr_pull_security_ace_object + (ndr, NDR_SCALARS, &r->object)); + break; } + default: { + break; } + } + } + if (ndr_flags & NDR_BUFFERS) { + if (!(ndr_flags & NDR_SCALARS)) { + /* We didn't get it above, and the token is not needed after this. */ +#ifdef SMB_HAS_NEW_NDR_PULL_STEAL_SWITCH + NDR_CHECK(ndr_pull_steal_switch_value(ndr, r, &level)); +#else + level = ndr_pull_steal_switch_value(ndr, r); +#endif + } + switch (level) { + case SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT: + NDR_CHECK(ndr_pull_security_ace_object + (ndr, NDR_BUFFERS, &r->object)); + break; + case SEC_ACE_TYPE_ACCESS_DENIED_OBJECT: + NDR_CHECK(ndr_pull_security_ace_object + (ndr, NDR_BUFFERS, &r->object)); + break; + case SEC_ACE_TYPE_SYSTEM_AUDIT_OBJECT: + NDR_CHECK(ndr_pull_security_ace_object + (ndr, NDR_BUFFERS, &r->object)); + break; + case SEC_ACE_TYPE_SYSTEM_ALARM_OBJECT: + NDR_CHECK(ndr_pull_security_ace_object + (ndr, NDR_BUFFERS, &r->object)); + break; + default: + break; + } + } + return NDR_ERR_SUCCESS; +} + +enum ndr_err_code +ndr_pull_dom_sid(struct ndr_pull *ndr, + int ndr_flags, + struct dom_sid *r) +{ + uint32_t cntr_sub_auths_0; + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_uint8(ndr, NDR_SCALARS, &r->sid_rev_num)); + NDR_CHECK(ndr_pull_int8(ndr, NDR_SCALARS, &r->num_auths)); + if (r->num_auths < 0 || r->num_auths > N_ELEMENTS(r->sub_auths)) { + return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range"); + } + NDR_CHECK(ndr_pull_array_uint8(ndr, NDR_SCALARS, r->id_auth, 6)); + memset(&r->sub_auths, 0, sizeof(r->sub_auths)); + for (cntr_sub_auths_0 = 0; + cntr_sub_auths_0 < r->num_auths; + cntr_sub_auths_0++) { + NDR_CHECK(ndr_pull_uint32 + (ndr, NDR_SCALARS, &r->sub_auths[cntr_sub_auths_0])); + } + } + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code +ndr_pull_security_ace(struct ndr_pull *ndr, + int ndr_flags, + struct security_ace *r) +{ + if (ndr_flags & NDR_SCALARS) { + uint32_t start_ofs = ndr->offset; + uint32_t size = 0; + uint32_t pad = 0; + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_security_ace_type(ndr, NDR_SCALARS, &r->type)); + NDR_CHECK(ndr_pull_security_ace_flags(ndr, NDR_SCALARS, &r->flags)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->access_mask)); + NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, r->type)); + NDR_CHECK(ndr_pull_security_ace_object_ctr + (ndr, NDR_SCALARS, &r->object)); + NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, &r->trustee)); + size = ndr->offset - start_ofs; + if (r->size < size) { + return ndr_pull_error(ndr, NDR_ERR_BUFSIZE, + "ndr_pull_security_ace: r->size %u < size %u", + (unsigned)r->size, size); + } + pad = r->size - size; + NDR_PULL_NEED_BYTES(ndr, pad); + ndr->offset += pad; + } + if (ndr_flags & NDR_BUFFERS) { + NDR_CHECK(ndr_pull_set_switch_value(ndr, &r->object, r->type)); + NDR_CHECK(ndr_pull_security_ace_object_ctr + (ndr, NDR_BUFFERS, &r->object)); + } + return NDR_ERR_SUCCESS; +} + +static enum ndr_err_code +ndr_pull_security_acl_revision(struct ndr_pull *ndr, + int ndr_flags, + enum security_acl_revision *r) +{ + uint16_t v; + NDR_CHECK(ndr_pull_enum_uint1632(ndr, ndr_flags, &v)); + *r = v; + return NDR_ERR_SUCCESS; +} + + +static enum ndr_err_code +ndr_pull_security_acl(struct ndr_pull *ndr, + int ndr_flags, + struct security_acl *r) +{ + uint32_t size_aces_0 = 0; + uint32_t cntr_aces_0; + TALLOC_CTX *_mem_save_aces_0; + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 4)); + NDR_CHECK(ndr_pull_security_acl_revision + (ndr, NDR_SCALARS, &r->revision)); + NDR_CHECK(ndr_pull_uint16(ndr, NDR_SCALARS, &r->size)); + NDR_CHECK(ndr_pull_uint32(ndr, NDR_SCALARS, &r->num_aces)); + if (r->num_aces > 2000) { + return ndr_pull_error(ndr, NDR_ERR_RANGE, "value out of range"); + } + size_aces_0 = r->num_aces; + NDR_PULL_ALLOC_N(ndr, r->aces, size_aces_0); + _mem_save_aces_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->aces, 0); + for (cntr_aces_0 = 0; cntr_aces_0 < size_aces_0; cntr_aces_0++) { + NDR_CHECK(ndr_pull_security_ace + (ndr, NDR_SCALARS, &r->aces[cntr_aces_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_aces_0, 0); + NDR_CHECK(ndr_pull_trailer_align(ndr, 4)); + } + if (ndr_flags & NDR_BUFFERS) { + size_aces_0 = r->num_aces; + _mem_save_aces_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->aces, 0); + for (cntr_aces_0 = 0; cntr_aces_0 < size_aces_0; cntr_aces_0++) { + NDR_CHECK(ndr_pull_security_ace + (ndr, NDR_BUFFERS, &r->aces[cntr_aces_0])); + } + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_aces_0, 0); + } + return NDR_ERR_SUCCESS; +} + + +static enum ndr_err_code +ndr_pull_security_descriptor_revision(struct ndr_pull *ndr, + int ndr_flags, + enum security_descriptor_revision *r) +{ + uint8_t v; + NDR_CHECK(ndr_pull_enum_uint8(ndr, ndr_flags, &v)); + *r = v; + return NDR_ERR_SUCCESS; +} + + + +static enum ndr_err_code +ndr_pull_security_descriptor_type(struct ndr_pull *ndr, + int ndr_flags, + uint16_t *r) +{ + uint16_t v; + NDR_CHECK(ndr_pull_uint16(ndr, ndr_flags, &v)); + *r = v; + return NDR_ERR_SUCCESS; +} + + +enum ndr_err_code +ndr_security_pull_security_descriptor(struct ndr_pull *ndr, + int ndr_flags, + struct security_descriptor *r) +{ + uint32_t _ptr_owner_sid; + TALLOC_CTX *_mem_save_owner_sid_0; + uint32_t _ptr_group_sid; + TALLOC_CTX *_mem_save_group_sid_0; + uint32_t _ptr_sacl; + TALLOC_CTX *_mem_save_sacl_0; + uint32_t _ptr_dacl; + TALLOC_CTX *_mem_save_dacl_0; + { + uint32_t _flags_save_STRUCT = ndr->flags; + ndr_set_flags(&ndr->flags, LIBNDR_FLAG_LITTLE_ENDIAN); + NDR_PULL_CHECK_FLAGS(ndr, ndr_flags); + if (ndr_flags & NDR_SCALARS) { + NDR_CHECK(ndr_pull_align(ndr, 5)); + NDR_CHECK(ndr_pull_security_descriptor_revision(ndr, + NDR_SCALARS, + &r->revision)); + NDR_CHECK(ndr_pull_security_descriptor_type(ndr, + NDR_SCALARS, + &r->type)); + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_owner_sid)); + if (_ptr_owner_sid) { + NDR_PULL_ALLOC(ndr, r->owner_sid); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, + r->owner_sid, + _ptr_owner_sid)); + } else { + r->owner_sid = NULL; + } + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_group_sid)); + if (_ptr_group_sid) { + NDR_PULL_ALLOC(ndr, r->group_sid); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, + r->group_sid, + _ptr_group_sid)); + } else { + r->group_sid = NULL; + } + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_sacl)); + if (_ptr_sacl) { + NDR_PULL_ALLOC(ndr, r->sacl); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->sacl, _ptr_sacl)); + } else { + r->sacl = NULL; + } + NDR_CHECK(ndr_pull_generic_ptr(ndr, &_ptr_dacl)); + if (_ptr_dacl) { + NDR_PULL_ALLOC(ndr, r->dacl); + NDR_CHECK(ndr_pull_relative_ptr1(ndr, r->dacl, _ptr_dacl)); + } else { + r->dacl = NULL; + } + NDR_CHECK(ndr_pull_trailer_align(ndr, 5)); + } + if (ndr_flags & NDR_BUFFERS) { + if (r->owner_sid) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->owner_sid)); + _mem_save_owner_sid_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->owner_sid, 0); + NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, r->owner_sid)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_owner_sid_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + if (r->group_sid) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->group_sid)); + _mem_save_group_sid_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->group_sid, 0); + NDR_CHECK(ndr_pull_dom_sid(ndr, NDR_SCALARS, r->group_sid)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_group_sid_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + if (r->sacl) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->sacl)); + _mem_save_sacl_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->sacl, 0); + NDR_CHECK(ndr_pull_security_acl(ndr, + NDR_SCALARS|NDR_BUFFERS, + r->sacl)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_sacl_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + if (r->dacl) { + uint32_t _relative_save_offset; + _relative_save_offset = ndr->offset; + NDR_CHECK(ndr_pull_relative_ptr2(ndr, r->dacl)); + _mem_save_dacl_0 = NDR_PULL_GET_MEM_CTX(ndr); + NDR_PULL_SET_MEM_CTX(ndr, r->dacl, 0); + NDR_CHECK(ndr_pull_security_acl(ndr, + NDR_SCALARS|NDR_BUFFERS, + r->dacl)); + NDR_PULL_SET_MEM_CTX(ndr, _mem_save_dacl_0, 0); + if (ndr->offset > ndr->relative_highest_offset) { + ndr->relative_highest_offset = ndr->offset; + } + ndr->offset = _relative_save_offset; + } + } + ndr->flags = _flags_save_STRUCT; + } + return NDR_ERR_SUCCESS; +} diff --git a/src/adldap/samba/ndr_security.h b/src/adldap/samba/ndr_security.h new file mode 100644 index 00000000..c799f979 --- /dev/null +++ b/src/adldap/samba/ndr_security.h @@ -0,0 +1,44 @@ +/* + * Unix SMB/CIFS implementation. + * Group Policy Object Support + * Copyright (C) Wilco Baan Hofman 2010 + * + * 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 + * (at your option) 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 . + */ + +/* + * This file is a copy of private samba sources. Parts of it + * were removed or edited. + */ + +#ifndef NDR_SECURITY_H +#define NDR_SECURITY_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include +#include + +enum ndr_err_code +ndr_security_pull_security_descriptor(struct ndr_pull *ndr, + int ndr_flags, + struct security_descriptor *r); + +#ifdef __cplusplus +} +#endif + +#endif /* NDR_SECURITY_H */ diff --git a/src/adldap/samba/replace.c b/src/adldap/samba/replace.c new file mode 100644 index 00000000..88849d9b --- /dev/null +++ b/src/adldap/samba/replace.c @@ -0,0 +1,54 @@ +/* + Unix SMB/CIFS implementation. + replacement routines for broken systems + Copyright (C) Andrew Tridgell 1992-1998 + Copyright (C) Jelmer Vernooij 2005-2008 + Copyright (C) Matthieu Patou 2010 + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +/* + * This file is a copy of private samba sources. Parts of it + * were removed or edited. + */ + +#include "replace.h" + +#include + +/* + * Like strncpy but does not 0 fill the buffer and always null + * terminates. bufsize is the size of the destination buffer. + * Returns the length of s. + */ +size_t rep_strlcpy(char *d, const char *s, size_t bufsize) +{ + size_t len = strlen(s); + size_t ret = len; + + if (bufsize <= 0) { + return 0; + } + if (len >= bufsize) { + len = bufsize - 1; + } + memcpy(d, s, len); + d[len] = 0; + return ret; +} diff --git a/src/adldap/samba/replace.h b/src/adldap/samba/replace.h new file mode 100644 index 00000000..5cb2c729 --- /dev/null +++ b/src/adldap/samba/replace.h @@ -0,0 +1,71 @@ +/* + Unix SMB/CIFS implementation. + + macros to go along with the lib/replace/ portability layer code + + Copyright (C) Andrew Tridgell 2005 + Copyright (C) Jelmer Vernooij 2006-2008 + Copyright (C) Jeremy Allison 2007. + + ** NOTE! The following LGPL license applies to the replace + ** library. This does NOT imply that all of Samba is released + ** under the LGPL + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see . +*/ + +/* + * This file is a copy of private samba sources. Parts of it + * were removed or edited. + */ + +#ifndef _LIBREPLACE_REPLACE_H +#define _LIBREPLACE_REPLACE_H + +#include +#include + +#ifndef __PRI64_PREFIX +# if __WORDSIZE == 64 && ! defined __APPLE__ +# define __PRI64_PREFIX "l" +# else +# define __PRI64_PREFIX "ll" +# endif +#endif + +#ifndef PRIu8 +# define PRIu8 "u" +#endif +#ifndef PRIu16 +# define PRIu16 "u" +#endif +#ifndef PRIu32 +# define PRIu32 "u" +#endif +#ifndef PRIu64 +# define PRIu64 __PRI64_PREFIX "u" +#endif + +#define strlcpy rep_strlcpy +size_t rep_strlcpy(char *d, const char *s, size_t bufsize); + +#ifndef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) +#endif + +#ifndef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#endif + +#endif /* _LIBREPLACE_REPLACE_H */ From a1a487b593fde2f32570a2469a2a1bc2503cb832 Mon Sep 17 00:00:00 2001 From: Dmitry Degtyarev Date: Wed, 7 Apr 2021 15:06:45 +0400 Subject: [PATCH 2/7] create and set sysvol security descriptor --- src/adldap/ad_defines.h | 1 + src/adldap/ad_interface.cpp | 62 ++++++++++++++++++++++++++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/adldap/ad_defines.h b/src/adldap/ad_defines.h index 2fb342af..11e17393 100644 --- a/src/adldap/ad_defines.h +++ b/src/adldap/ad_defines.h @@ -165,6 +165,7 @@ enum SystemFlagsBit { #define ATTRIBUTE_IP_PHONE "ipPhone" #define ATTRIBUTE_OTHER_IP_PHONE "otherIpPhone" #define ATTRIBUTE_UPN_SUFFIXES "uPNSuffixes" +#define ATTRIBUTE_SECURITY_DESCRIPTOR "nTSecurityDescriptor" #define CLASS_GROUP "group" #define CLASS_USER "user" diff --git a/src/adldap/ad_interface.cpp b/src/adldap/ad_interface.cpp index 94198223..fbd369d6 100644 --- a/src/adldap/ad_interface.cpp +++ b/src/adldap/ad_interface.cpp @@ -23,6 +23,9 @@ #include "ad_utils.h" #include "ad_object.h" #include "ad_display.h" +#include "samba/ndr_security.h" +#include "samba/gp_manage.h" +#include "samba/dom_sid.h" #include #include @@ -1052,7 +1055,64 @@ bool AdInterface::create_gpo(const QString &display_name) { return false; } - // TODO: security descriptor. Samba does this: get nTSecurityDescriptor attribute from the gpo object as raw bytes, then sets the security descriptor of the sysvol dir to that value. Currently not doing that, so security descriptor of sysvol dir is the default one, which is ... bad? Not sure. Problem is, libsmbclient only provides a way to set security descriptor using key/value strings, not the raw bytes basically. So to do it that way would need to decode object security descriptor. Samba source has that implemented internally but not exposed as a usable lib. Probably SHOULD set security descriptor because who knows what the default is, what if it's just randomly modifiable by any user. Also, the security descriptor functionality will be needed for "Security" tab in ADMC at some point. So should either implement all of that stuff (it's a lot...) or hopefully find some lib to use (unlikely). On Windows you would just use Microsoft's lib. + // + // Set security descriptor for sysvol dir + // + + // First get descriptor of the GPO + const QHash search_results = search(QString(), {ATTRIBUTE_SECURITY_DESCRIPTOR}, SearchScope_Object, dn); + const AdObject object = search_results[dn]; + const QByteArray descriptor_bytes = object.get_value(ATTRIBUTE_SECURITY_DESCRIPTOR); + + // Transform descriptor bytes into descriptor struct + TALLOC_CTX *tmp_ctx = talloc_new(NULL); + + DATA_BLOB blob; + blob.data = (uint8_t *)descriptor_bytes.data(); + blob.length = descriptor_bytes.size(); + + struct ndr_pull *ndr_pull = ndr_pull_init_blob(&blob, tmp_ctx); + + struct security_descriptor domain_sd; + ndr_security_pull_security_descriptor(ndr_pull, NDR_SCALARS|NDR_BUFFERS, &domain_sd); + + // Create sysvol descriptor from domain descriptor (not + // one to one, some modifications are needed) + struct security_descriptor *sysvol_sd; + gp_create_gpt_security_descriptor(tmp_ctx, &domain_sd, &sysvol_sd); + + const QString sysvol_sd_string = + [tmp_ctx, &sysvol_sd]() { + QString out; + + out += QString("REVISION:%1,OWNER:%2,GROUP:%3,").arg(QString::number(sysvol_sd->revision), dom_sid_string(tmp_ctx, sysvol_sd->owner_sid), dom_sid_string(tmp_ctx, sysvol_sd->group_sid)); + + // NOTE: don't need sacl + + for (uint32_t i = 0; i < sysvol_sd->dacl->num_aces; i++) { + struct security_ace ace = sysvol_sd->dacl->aces[i]; + + char access_mask_buffer[100]; + snprintf(access_mask_buffer, sizeof(access_mask_buffer), "0x%08x", ace.access_mask); + + if (i > 0) { + out += ","; + } + + out += QString("ACL:%1:%2/%3/%4").arg(dom_sid_string(tmp_ctx, &ace.trustee), QString::number(ace.type), QString::number(ace.flags), access_mask_buffer); + } + + return out; + }(); + const QByteArray sysvol_sd_string_bytes = sysvol_sd_string.toUtf8(); + const char *sysvol_sd_cstr = sysvol_sd_string_bytes.constData(); + + // Set descriptor + const int result = smbc_setxattr(cstr(main_dir), "", sysvol_sd_cstr, sysvol_sd_string_bytes.size(), 0); + + qInfo() << "smbc_setxattr result = " << result; + + talloc_free(tmp_ctx); return true; } From 25cf32cea63689b8b8e5d50d1401e26d72fa3afe Mon Sep 17 00:00:00 2001 From: Dmitry Degtyarev Date: Wed, 7 Apr 2021 16:14:43 +0400 Subject: [PATCH 3/7] add create policy dialog use it to implement creating policies add dn output to create_gpo() --- src/adldap/ad_interface.cpp | 3 +- src/adldap/ad_interface.h | 3 +- src/admc/CMakeLists.txt | 1 + src/admc/central_widget.cpp | 41 ++++++++++-- src/admc/central_widget.h | 1 + src/admc/create_policy_dialog.cpp | 104 ++++++++++++++++++++++++++++++ src/admc/create_policy_dialog.h | 50 ++++++++++++++ tests/CMakeLists.txt | 1 + 8 files changed, 196 insertions(+), 8 deletions(-) create mode 100644 src/admc/create_policy_dialog.cpp create mode 100644 src/admc/create_policy_dialog.h diff --git a/src/adldap/ad_interface.cpp b/src/adldap/ad_interface.cpp index fbd369d6..b78ad421 100644 --- a/src/adldap/ad_interface.cpp +++ b/src/adldap/ad_interface.cpp @@ -964,7 +964,7 @@ bool AdInterface::user_unlock(const QString &dn) { } } -bool AdInterface::create_gpo(const QString &display_name) { +bool AdInterface::create_gpo(const QString &display_name, QString &dn_out) { // // Generate UUID used for directory and object names // @@ -1025,6 +1025,7 @@ bool AdInterface::create_gpo(const QString &display_name) { // // TODO: add all attributes during creation, need to directly create through ldap then const QString dn = QString("CN=%1,CN=Policies,CN=System,%2").arg(uuid, d->domain_head); + dn_out = dn; const bool result_add = object_add(dn, CLASS_GP_CONTAINER); if (!result_add) { return false; diff --git a/src/adldap/ad_interface.h b/src/adldap/ad_interface.h index 526c098f..362494c6 100644 --- a/src/adldap/ad_interface.h +++ b/src/adldap/ad_interface.h @@ -158,7 +158,8 @@ public: bool user_set_account_option(const QString &dn, AccountOption option, bool set); bool user_unlock(const QString &dn); - bool create_gpo(const QString &name); + // "dn_out" is set to the dn of created gpo + bool create_gpo(const QString &name, QString &dn_out); bool delete_gpo(const QString &dn); QString sysvol_path_to_smb(const QString &sysvol_path) const; diff --git a/src/admc/CMakeLists.txt b/src/admc/CMakeLists.txt index fb734470..c2e3b165 100644 --- a/src/admc/CMakeLists.txt +++ b/src/admc/CMakeLists.txt @@ -46,6 +46,7 @@ add_executable(admc about_dialog.cpp manual_dialog.cpp select_policy_dialog.cpp + create_policy_dialog.cpp gplink.cpp filter_widget/filter_widget.cpp diff --git a/src/admc/central_widget.cpp b/src/admc/central_widget.cpp index 8f68416e..9ede4be7 100644 --- a/src/admc/central_widget.cpp +++ b/src/admc/central_widget.cpp @@ -32,6 +32,7 @@ #include "status.h" #include "rename_dialog.h" #include "create_dialog.h" +#include "create_policy_dialog.h" #include "move_dialog.h" #include "find_dialog.h" #include "password_dialog.h" @@ -253,12 +254,7 @@ void CentralWidget::go_online(AdInterface &ad) { const QHash search_results = ad.search(filter, search_attributes, SearchScope_All); for (const AdObject &object : search_results.values()) { - QStandardItem *scope_item; - QList results_row; - console_widget->add_buddy_scope_and_results(policies_results_id, ScopeNodeType_Static, policies_item->index(), &scope_item, &results_row); - - setup_policy_scope_item(scope_item, object); - setup_policy_results_row(results_row, object); + add_policy_to_console(object); } console_widget->sort_scope(); @@ -471,6 +467,30 @@ void CentralWidget::edit_upn_suffixes() { void CentralWidget::create_policy() { // TODO: implement using ad.create_gpo() (which is // unfinished) + + auto dialog = new CreatePolicyDialog(this); + + connect( + dialog, &QDialog::accepted, + [this, dialog]() { + AdInterface ad; + if (ad_failed(ad)) { + return; + } + + const QString dn = dialog->get_created_dn(); + + const QList search_attributes = policy_model_search_attributes(); + const QHash search_results = ad.search(QString(), search_attributes, SearchScope_Object, dn); + const AdObject object = search_results[dn]; + + add_policy_to_console(object); + + // NOTE: not adding policy object to the domain + // tree, but i think it's ok? + }); + + dialog->open(); } void CentralWidget::rename_policy() { @@ -1058,3 +1078,12 @@ QList CentralWidget::get_selected_dns() { return selected.keys(); } + +void CentralWidget::add_policy_to_console(const AdObject &object) { + QStandardItem *scope_item; + QList results_row; + console_widget->add_buddy_scope_and_results(policies_results_id, ScopeNodeType_Static, policies_index, &scope_item, &results_row); + + setup_policy_scope_item(scope_item, object); + setup_policy_results_row(results_row, object); +} diff --git a/src/admc/central_widget.h b/src/admc/central_widget.h index 4aea55d3..342c50e9 100644 --- a/src/admc/central_widget.h +++ b/src/admc/central_widget.h @@ -128,6 +128,7 @@ private: void create_helper(const QString &object_class); QHash get_selected_dns_and_indexes(); QList get_selected_dns(); + void add_policy_to_console(const AdObject &object); }; #endif /* CENTRAL_WIDGET_H */ diff --git a/src/admc/create_policy_dialog.cpp b/src/admc/create_policy_dialog.cpp new file mode 100644 index 00000000..b1b1e112 --- /dev/null +++ b/src/admc/create_policy_dialog.cpp @@ -0,0 +1,104 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020 BaseALT Ltd. + * + * 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 + * (at your option) 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 . + */ + +#include "create_policy_dialog.h" + +#include "adldap.h" +#include "status.h" + +#include +#include +#include +#include + +// TODO: implement checkbox for account option "User cannot change password". Can't just do it through UAC attribute bits. + +// TODO: not sure about how required_edits are done, maybe +// just do this through verify()? Had to remove upnedit from +// required_edits because that's a list of stringedits. Now upnedit checks that it's not empty in verify(); + +CreatePolicyDialog::CreatePolicyDialog(QWidget *parent) +: QDialog(parent) +{ + setAttribute(Qt::WA_DeleteOnClose); + + setMinimumWidth(400); + + const auto title = QString(tr("Create GPO")); + setWindowTitle(title); + + name_edit = new QLineEdit(); + name_edit->setText("New Group Policy Object"); + + const auto edits_layout = new QFormLayout(); + edits_layout->addRow(tr("Name"), name_edit); + + auto create_button = new QPushButton(tr("Create")); + + const auto layout = new QVBoxLayout(); + setLayout(layout); + layout->addLayout(edits_layout); + layout->addWidget(create_button); + + connect( + create_button, &QAbstractButton::clicked, + this, &CreatePolicyDialog::accept); +} + +QString CreatePolicyDialog::get_created_dn() const { + return created_dn; +} + +void CreatePolicyDialog::accept() { + AdInterface ad; + if (ad_failed(ad)) { + return; + } + + show_busy_indicator(); + + const QString name = name_edit->text(); + + // NOTE: since this is *display name*, not just name, + // have to manually check for conflict. Server wouldn't + // catch this. + const bool name_conflict = + [&]() { + const QString filter = filter_CONDITION(Condition_Equals, ATTRIBUTE_DISPLAY_NAME, name); + const QHash results = ad.search(filter, QList(), SearchScope_All); + + return !results.isEmpty(); + }(); + + if (name_conflict) { + QMessageBox::warning(this, tr("Error"), tr("Group Policy Object with this name already exists.")); + + return; + } + + const bool success = ad.create_gpo(name, created_dn); + + hide_busy_indicator(); + + STATUS()->display_ad_messages(ad, this); + + if (success) { + QDialog::accept(); + } +} diff --git a/src/admc/create_policy_dialog.h b/src/admc/create_policy_dialog.h new file mode 100644 index 00000000..034b46d1 --- /dev/null +++ b/src/admc/create_policy_dialog.h @@ -0,0 +1,50 @@ +/* + * ADMC - AD Management Center + * + * Copyright (C) 2020 BaseALT Ltd. + * + * 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 + * (at your option) 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 . + */ + +#ifndef CREATE_POLICY_DIALOG_H +#define CREATE_POLICY_DIALOG_H + +/** + * Creates a GPO. + */ + +#include +#include +#include + +class QLineEdit; + +class CreatePolicyDialog : public QDialog { +Q_OBJECT + +public: + CreatePolicyDialog(QWidget *parent); + + QString get_created_dn() const; + +public slots: + void accept(); + +private: + QLineEdit *name_edit; + QString created_dn; + +}; + +#endif /* CREATE_POLICY_DIALOG_H */ diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 5b84c7fe..3742990f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -52,6 +52,7 @@ set(TEST_SOURCES ${PROJECT_SOURCE_DIR}/src/admc/about_dialog.cpp ${PROJECT_SOURCE_DIR}/src/admc/manual_dialog.cpp ${PROJECT_SOURCE_DIR}/src/admc/select_policy_dialog.cpp + ${PROJECT_SOURCE_DIR}/src/admc/create_policy_dialog.cpp ${PROJECT_SOURCE_DIR}/src/admc/gplink.cpp ${PROJECT_SOURCE_DIR}/src/admc/filter_widget/filter_widget.cpp From 7fb6d1d9350aaaa54874938042c08f7263b6d106 Mon Sep 17 00:00:00 2001 From: Dmitry Degtyarev Date: Wed, 7 Apr 2021 17:26:36 +0400 Subject: [PATCH 4/7] remove debug print --- src/adldap/ad_interface.cpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/adldap/ad_interface.cpp b/src/adldap/ad_interface.cpp index b78ad421..43349a62 100644 --- a/src/adldap/ad_interface.cpp +++ b/src/adldap/ad_interface.cpp @@ -1111,8 +1111,6 @@ bool AdInterface::create_gpo(const QString &display_name, QString &dn_out) { // Set descriptor const int result = smbc_setxattr(cstr(main_dir), "", sysvol_sd_cstr, sysvol_sd_string_bytes.size(), 0); - qInfo() << "smbc_setxattr result = " << result; - talloc_free(tmp_ctx); return true; From f0b731ad617e36358b22bc0452b535a560282b05 Mon Sep 17 00:00:00 2001 From: Dmitry Degtyarev Date: Wed, 7 Apr 2021 17:37:53 +0400 Subject: [PATCH 5/7] add buildrequires samba-devel --- .gear/admc.spec | 1 + 1 file changed, 1 insertion(+) diff --git a/.gear/admc.spec b/.gear/admc.spec index f3fe24b5..1e284bfc 100644 --- a/.gear/admc.spec +++ b/.gear/admc.spec @@ -17,6 +17,7 @@ BuildRequires(pre): qt5-tools-devel BuildRequires(pre): catch2-devel BuildRequires(pre): cmake-modules +BuildRequires: samba-devel BuildRequires: libldap-devel BuildRequires: libsasl2-devel BuildRequires: libsmbclient-devel From 71ff81a17ae3e54808b5e00c2e46d554e9136269 Mon Sep 17 00:00:00 2001 From: Dmitry Degtyarev Date: Wed, 7 Apr 2021 17:50:40 +0400 Subject: [PATCH 6/7] add samba-devel to dockerfile --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index bf9c1498..4e122eb9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,7 +2,7 @@ FROM alt:p9 RUN apt-get update \ -&& apt-get install -y qt5-base-devel cmake qt5-tools-devel qt5-tools libuuid-devel libsmbclient-devel libsasl2-devel catch2-devel doxygen glib2-devel libpcre-devel rpm-build gear libldap-devel libcmocka-devel libkrb5-devel \ +&& apt-get install -y qt5-base-devel cmake qt5-tools-devel qt5-tools libuuid-devel libsmbclient-devel libsasl2-devel catch2-devel doxygen glib2-devel libpcre-devel rpm-build gear libldap-devel libcmocka-devel libkrb5-devel samba-devel \ && useradd -ms /bin/bash builder && mkdir /app && chown root:builder /app # Copies your code file from your action repository to the filesystem path `/` of the container From 779ba26a3f677c3a4c85d15597523017c613b181 Mon Sep 17 00:00:00 2001 From: Dmitry Degtyarev Date: Wed, 7 Apr 2021 17:51:41 +0400 Subject: [PATCH 7/7] remove unused var --- src/adldap/ad_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/adldap/ad_interface.cpp b/src/adldap/ad_interface.cpp index 43349a62..a25770cd 100644 --- a/src/adldap/ad_interface.cpp +++ b/src/adldap/ad_interface.cpp @@ -1109,7 +1109,7 @@ bool AdInterface::create_gpo(const QString &display_name, QString &dn_out) { const char *sysvol_sd_cstr = sysvol_sd_string_bytes.constData(); // Set descriptor - const int result = smbc_setxattr(cstr(main_dir), "", sysvol_sd_cstr, sysvol_sd_string_bytes.size(), 0); + smbc_setxattr(cstr(main_dir), "", sysvol_sd_cstr, sysvol_sd_string_bytes.size(), 0); talloc_free(tmp_ctx);