s4:dsdb: Implement msDS-ManagedPassword attribute
[Samba.git] / source4 / dsdb / samdb / ldb_modules / managed_pwd.c
blobcb3fffc0143d3229e17282d6055f0a45c124dbf8
1 /*
2 Unix SMB/CIFS implementation.
3 msDS-ManagedPassword attribute for Group Managed Service Accounts
5 Copyright (C) Catalyst.Net Ltd 2024
7 This program is free software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program. If not, see <https://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include <talloc.h>
23 #include <ldb.h>
24 #include <ldb_module.h>
25 #include <ldb_errors.h>
26 #include <ldb_private.h>
27 #include "lib/crypto/gmsa.h"
28 #include "lib/util/time.h"
29 #include "librpc/gen_ndr/ndr_gkdi.h"
30 #include "librpc/gen_ndr/ndr_gmsa.h"
31 #include "dsdb/gmsa/util.h"
32 #include "dsdb/samdb/ldb_modules/managed_pwd.h"
33 #include "dsdb/samdb/ldb_modules/util.h"
34 #include "dsdb/samdb/samdb.h"
36 #undef strcasecmp
38 static int gmsa_managed_password(struct ldb_context *const ldb,
39 struct ldb_message *msg,
40 struct ldb_request *req,
41 struct ldb_reply *ares)
43 TALLOC_CTX *tmp_ctx = NULL;
44 const struct dsdb_encrypted_connection_state *conn_state = NULL;
45 int ret = LDB_SUCCESS;
46 NTSTATUS status = NT_STATUS_OK;
47 NTTIME current_time;
48 struct gmsa_update *gmsa_update = NULL;
49 struct gmsa_return_pwd return_pwd;
50 bool ok;
53 * Prevent viewing msDS-ManagedPassword over an insecure connection. The
54 * opaque is added in the ldap backend init.
56 conn_state = ldb_get_opaque(
57 ldb, DSDB_OPAQUE_ENCRYPTED_CONNECTION_STATE_NAME);
58 if (conn_state != NULL && !conn_state->using_encrypted_connection) {
59 ret = dsdb_werror(ldb,
60 LDB_ERR_OPERATIONS_ERROR,
61 WERR_DS_CONFIDENTIALITY_REQUIRED,
62 "Viewing msDS-ManagedPassword requires an "
63 "encrypted connection");
64 goto out;
68 /* Is the account a Group Managed Service Account? */
69 const bool is_gmsa = dsdb_account_is_gmsa(ldb, msg);
70 if (!is_gmsa) {
71 /* It’s not a GMSA — we’re done here. */
72 ret = LDB_SUCCESS;
73 goto out;
78 bool am_rodc = true;
80 /* Are we operating as an RODC? */
81 ret = samdb_rodc(ldb, &am_rodc);
82 if (ret != LDB_SUCCESS) {
83 DBG_WARNING("unable to tell if we are an RODC\n");
84 goto out;
87 if (am_rodc) {
88 /* TODO: forward the request to a writable DC. */
89 ret = ldb_error(
90 ldb,
91 LDB_ERR_OPERATIONS_ERROR,
92 "msDS-ManagedPassword may only be viewed on a "
93 "writeable DC, not an RODC");
94 goto out;
98 tmp_ctx = talloc_new(msg);
99 if (tmp_ctx == NULL) {
100 ret = ldb_oom(ldb);
101 goto out;
105 struct dom_sid account_sid;
106 bool allowed_to_view = false;
108 ret = samdb_result_dom_sid_buf(msg, "objectSid", &account_sid);
109 if (ret) {
110 goto out;
113 ret = gmsa_allowed_to_view_managed_password(
114 tmp_ctx, ldb, msg, &account_sid, &allowed_to_view);
115 if (ret) {
116 goto out;
119 if (!allowed_to_view) {
120 /* Sorry, you can’t view the password. */
121 goto out;
125 ok = dsdb_gmsa_current_time(ldb, &current_time);
126 if (!ok) {
127 ret = ldb_operr(ldb);
128 goto out;
131 ret = gmsa_recalculate_managed_pwd(
132 tmp_ctx, ldb, msg, current_time, &gmsa_update, &return_pwd);
133 if (ret) {
134 goto out;
137 SMB_ASSERT(return_pwd.new_pwd != NULL);
140 DATA_BLOB packed_blob = {};
142 status = gmsa_pack_managed_pwd(
143 tmp_ctx,
144 return_pwd.new_pwd->buf,
145 return_pwd.prev_pwd != NULL ? return_pwd.prev_pwd->buf
146 : NULL,
147 return_pwd.query_interval,
148 return_pwd.unchanged_interval,
149 &packed_blob);
150 if (!NT_STATUS_IS_OK(status)) {
151 ret = ldb_operr(ldb);
152 goto out;
155 ret = ldb_msg_add_steal_value(msg,
156 "msDS-ManagedPassword",
157 &packed_blob);
158 if (ret) {
159 goto out;
163 out:
164 TALLOC_FREE(tmp_ctx);
165 return ret;
168 int constructed_msds_managed_password(struct ldb_module *module,
169 struct ldb_message *msg,
170 enum ldb_scope scope,
171 struct ldb_request *parent,
172 struct ldb_reply *ares)
174 return gmsa_managed_password(ldb_module_get_ctx(module),
175 msg,
176 parent,
177 ares);