From 532789b4f3f0efe5350089391a97f24296f3be90 Mon Sep 17 00:00:00 2001 From: Jo Sutton Date: Tue, 13 Feb 2024 15:45:21 +1300 Subject: [PATCH] s4:dsdb: Implement msDS-ManagedPassword attribute Signed-off-by: Jo Sutton Reviewed-by: Andrew Bartlett Autobuild-User(master): Andrew Bartlett Autobuild-Date(master): Tue Apr 16 05:02:30 UTC 2024 on atb-devel-224 --- selftest/knownfail.d/gmsa | 11 +- selftest/knownfail.d/user_getpassword_gmsa | 3 - source4/dsdb/samdb/ldb_modules/managed_pwd.c | 178 +++++++++++++++++++++ source4/dsdb/samdb/ldb_modules/managed_pwd.h | 33 ++++ source4/dsdb/samdb/ldb_modules/operational.c | 18 ++- .../dsdb/samdb/ldb_modules/wscript_build_server | 4 +- source4/dsdb/samdb/samdb.h | 5 +- 7 files changed, 234 insertions(+), 18 deletions(-) rewrite selftest/knownfail.d/gmsa (93%) create mode 100644 source4/dsdb/samdb/ldb_modules/managed_pwd.c create mode 100644 source4/dsdb/samdb/ldb_modules/managed_pwd.h diff --git a/selftest/knownfail.d/gmsa b/selftest/knownfail.d/gmsa dissimilarity index 93% index 31b0c869db7..7a126d6cc22 100644 --- a/selftest/knownfail.d/gmsa +++ b/selftest/knownfail.d/gmsa @@ -1,10 +1 @@ -^samba.tests.dckeytab.samba.tests.dckeytab.DCKeytabTests.test_export_keytab_gmsa -^samba.tests.blackbox.gmsa.samba.tests.blackbox.gmsa.GMSABlackboxTest.test_gmsa_password_access -^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password\(ad_dc:local\)$ -^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_allowed\(ad_dc:local\)$ -^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_during_clock_skew_window_when_current_key_is_expired\(ad_dc:local\)$ -^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_during_clock_skew_window_when_current_key_is_valid\(ad_dc:local\)$ -^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_during_clock_skew_window_when_next_key_is_expired\(ad_dc:local\)$ -^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_when_current_key_is_expired\(ad_dc:local\)$ -^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_when_current_key_is_valid\(ad_dc:local\)$ -^samba.tests.krb5.gmsa_tests.samba.tests.krb5.gmsa_tests.GmsaTests.test_retrieved_password_when_next_key_is_expired\(ad_dc:local\)$ +^samba.tests.dckeytab.samba.tests.dckeytab.DCKeytabTests.test_export_keytab_gmsa diff --git a/selftest/knownfail.d/user_getpassword_gmsa b/selftest/knownfail.d/user_getpassword_gmsa index dd28e61d9b5..a9d4afe9ea8 100644 --- a/selftest/knownfail.d/user_getpassword_gmsa +++ b/selftest/knownfail.d/user_getpassword_gmsa @@ -1,6 +1,3 @@ -^samba.tests.samba_tool.user_getpassword_gmsa.samba.tests.samba_tool.user_getpassword_gmsa.GMSAPasswordTest.test_getpassword\(ad_dc_default\) -^samba.tests.samba_tool.user_getpassword_gmsa.samba.tests.samba_tool.user_getpassword_gmsa.GMSAPasswordTest.test_querytime\(ad_dc_default\) -^samba.tests.samba_tool.user_getpassword_gmsa.samba.tests.samba_tool.user_getpassword_gmsa.GMSAPasswordTest.test_querytime_unixtime\(ad_dc_default\) ^samba.tests.samba_tool.user_getpassword_gmsa.samba.tests.samba_tool.user_getpassword_gmsa.GMSAPasswordTest.test_unicode_pwd\(ad_dc_default\) ^samba.tests.samba_tool.user_getpassword_gmsa.samba.tests.samba_tool.user_getpassword_gmsa.GMSAPasswordTest.test_utf16_password\(ad_dc_default\) ^samba.tests.samba_tool.user_getpassword_gmsa.samba.tests.samba_tool.user_getpassword_gmsa.GMSAPasswordTest.test_utf8_password\(ad_dc_default\) diff --git a/source4/dsdb/samdb/ldb_modules/managed_pwd.c b/source4/dsdb/samdb/ldb_modules/managed_pwd.c new file mode 100644 index 00000000000..cb3fffc0143 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/managed_pwd.c @@ -0,0 +1,178 @@ +/* + Unix SMB/CIFS implementation. + msDS-ManagedPassword attribute for Group Managed Service Accounts + + Copyright (C) Catalyst.Net Ltd 2024 + + 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 "includes.h" +#include +#include +#include +#include +#include +#include "lib/crypto/gmsa.h" +#include "lib/util/time.h" +#include "librpc/gen_ndr/ndr_gkdi.h" +#include "librpc/gen_ndr/ndr_gmsa.h" +#include "dsdb/gmsa/util.h" +#include "dsdb/samdb/ldb_modules/managed_pwd.h" +#include "dsdb/samdb/ldb_modules/util.h" +#include "dsdb/samdb/samdb.h" + +#undef strcasecmp + +static int gmsa_managed_password(struct ldb_context *const ldb, + struct ldb_message *msg, + struct ldb_request *req, + struct ldb_reply *ares) +{ + TALLOC_CTX *tmp_ctx = NULL; + const struct dsdb_encrypted_connection_state *conn_state = NULL; + int ret = LDB_SUCCESS; + NTSTATUS status = NT_STATUS_OK; + NTTIME current_time; + struct gmsa_update *gmsa_update = NULL; + struct gmsa_return_pwd return_pwd; + bool ok; + + /* + * Prevent viewing msDS-ManagedPassword over an insecure connection. The + * opaque is added in the ldap backend init. + */ + conn_state = ldb_get_opaque( + ldb, DSDB_OPAQUE_ENCRYPTED_CONNECTION_STATE_NAME); + if (conn_state != NULL && !conn_state->using_encrypted_connection) { + ret = dsdb_werror(ldb, + LDB_ERR_OPERATIONS_ERROR, + WERR_DS_CONFIDENTIALITY_REQUIRED, + "Viewing msDS-ManagedPassword requires an " + "encrypted connection"); + goto out; + } + + { + /* Is the account a Group Managed Service Account? */ + const bool is_gmsa = dsdb_account_is_gmsa(ldb, msg); + if (!is_gmsa) { + /* It’s not a GMSA — we’re done here. */ + ret = LDB_SUCCESS; + goto out; + } + } + + { + bool am_rodc = true; + + /* Are we operating as an RODC? */ + ret = samdb_rodc(ldb, &am_rodc); + if (ret != LDB_SUCCESS) { + DBG_WARNING("unable to tell if we are an RODC\n"); + goto out; + } + + if (am_rodc) { + /* TODO: forward the request to a writable DC. */ + ret = ldb_error( + ldb, + LDB_ERR_OPERATIONS_ERROR, + "msDS-ManagedPassword may only be viewed on a " + "writeable DC, not an RODC"); + goto out; + } + } + + tmp_ctx = talloc_new(msg); + if (tmp_ctx == NULL) { + ret = ldb_oom(ldb); + goto out; + } + + { + struct dom_sid account_sid; + bool allowed_to_view = false; + + ret = samdb_result_dom_sid_buf(msg, "objectSid", &account_sid); + if (ret) { + goto out; + } + + ret = gmsa_allowed_to_view_managed_password( + tmp_ctx, ldb, msg, &account_sid, &allowed_to_view); + if (ret) { + goto out; + } + + if (!allowed_to_view) { + /* Sorry, you can’t view the password. */ + goto out; + } + } + + ok = dsdb_gmsa_current_time(ldb, ¤t_time); + if (!ok) { + ret = ldb_operr(ldb); + goto out; + } + + ret = gmsa_recalculate_managed_pwd( + tmp_ctx, ldb, msg, current_time, &gmsa_update, &return_pwd); + if (ret) { + goto out; + } + + SMB_ASSERT(return_pwd.new_pwd != NULL); + + { + DATA_BLOB packed_blob = {}; + + status = gmsa_pack_managed_pwd( + tmp_ctx, + return_pwd.new_pwd->buf, + return_pwd.prev_pwd != NULL ? return_pwd.prev_pwd->buf + : NULL, + return_pwd.query_interval, + return_pwd.unchanged_interval, + &packed_blob); + if (!NT_STATUS_IS_OK(status)) { + ret = ldb_operr(ldb); + goto out; + } + + ret = ldb_msg_add_steal_value(msg, + "msDS-ManagedPassword", + &packed_blob); + if (ret) { + goto out; + } + } + +out: + TALLOC_FREE(tmp_ctx); + return ret; +} + +int constructed_msds_managed_password(struct ldb_module *module, + struct ldb_message *msg, + enum ldb_scope scope, + struct ldb_request *parent, + struct ldb_reply *ares) +{ + return gmsa_managed_password(ldb_module_get_ctx(module), + msg, + parent, + ares); +} diff --git a/source4/dsdb/samdb/ldb_modules/managed_pwd.h b/source4/dsdb/samdb/ldb_modules/managed_pwd.h new file mode 100644 index 00000000000..4750ea53798 --- /dev/null +++ b/source4/dsdb/samdb/ldb_modules/managed_pwd.h @@ -0,0 +1,33 @@ +/* + Unix SMB/CIFS implementation. + msDS-ManagedPassword attribute for Group Managed Service Accounts + + Copyright (C) Catalyst.Net Ltd 2024 + + 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 DSDB_SAMDB_LDB_MODULES_MANAGED_PWD_H +#define DSDB_SAMDB_LDB_MODULES_MANAGED_PWD_H + +#include + +struct ldb_module; +int constructed_msds_managed_password(struct ldb_module *module, + struct ldb_message *msg, + enum ldb_scope scope, + struct ldb_request *parent, + struct ldb_reply *ares); + +#endif /* DSDB_SAMDB_LDB_MODULES_MANAGED_PWD_H */ diff --git a/source4/dsdb/samdb/ldb_modules/operational.c b/source4/dsdb/samdb/ldb_modules/operational.c index 9b56de2ae5b..4e9ece53643 100644 --- a/source4/dsdb/samdb/ldb_modules/operational.c +++ b/source4/dsdb/samdb/ldb_modules/operational.c @@ -71,6 +71,7 @@ #include "librpc/gen_ndr/ndr_misc.h" #include "librpc/gen_ndr/ndr_drsblobs.h" #include "dsdb/samdb/samdb.h" +#include "dsdb/samdb/ldb_modules/managed_pwd.h" #include "dsdb/samdb/ldb_modules/util.h" #include "auth/auth.h" @@ -1411,6 +1412,17 @@ static const char *resultant_pso_computed_attrs[] = NULL }; +static const char *managed_password_computed_attrs[] = { + "msDS-GroupMSAMembership", + "msDS-ManagedPasswordId", + "msDS-ManagedPasswordInterval", + "msDS-ManagedPasswordPreviousId", + "objectClass", + "objectSid", + "whenCreated", + NULL, +}; + /* a list of attribute names that are hidden, but can be searched for using another (non-hidden) name to produce the correct result @@ -1433,7 +1445,11 @@ static const struct op_attributes_replace search_sub[] = { { "msDS-UserPasswordExpiryTimeComputed", "userAccountControl", user_password_expiry_time_computed_attrs, construct_msds_user_password_expiry_time_computed }, { "msDS-ResultantPSO", "objectClass", resultant_pso_computed_attrs, - construct_resultant_pso } + construct_resultant_pso }, + {"msDS-ManagedPassword", + NULL, + managed_password_computed_attrs, + constructed_msds_managed_password}, }; diff --git a/source4/dsdb/samdb/ldb_modules/wscript_build_server b/source4/dsdb/samdb/ldb_modules/wscript_build_server index 7a63f43726b..9c1eb12a7c2 100644 --- a/source4/dsdb/samdb/ldb_modules/wscript_build_server +++ b/source4/dsdb/samdb/ldb_modules/wscript_build_server @@ -360,12 +360,12 @@ bld.SAMBA_MODULE('ldb_instancetype', bld.SAMBA_MODULE('ldb_operational', - source='operational.c', + source='operational.c managed_pwd.c', subsystem='ldb', init_function='ldb_operational_module_init', module_init_name='ldb_init_module', internal_module=False, - deps='talloc samba-util samdb-common DSDB_MODULE_HELPERS samdb' + deps='talloc samba-util samdb-common DSDB_MODULE_HELPERS samdb gkdi gmsa NDR_GKDI NDR_GMSA' ) diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index e3558c12709..64135ef704f 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -31,11 +31,9 @@ struct loadparm_context; struct tevent_context; struct tsocket_address; struct dsdb_trust_routing_table; -struct gmsa_update_pwd; struct gmsa_update_pwd_part; struct gmsa_update; struct gmsa_return_pwd; -struct RootKey; struct KeyEnvelope; enum dsdb_password_checked { @@ -44,10 +42,13 @@ enum dsdb_password_checked { DSDB_PASSWORD_CHECKED_AND_CORRECT }; +#include "lib/util/data_blob.h" #include "librpc/gen_ndr/security.h" #include #include "lib/ldb-samba/ldif_handlers.h" +#include "lib/util/time.h" #include "librpc/gen_ndr/samr.h" +#include "libcli/util/werror.h" #include "librpc/gen_ndr/drsuapi.h" #include "librpc/gen_ndr/drsblobs.h" #include "dsdb/schema/schema.h" -- 2.11.4.GIT