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/>.
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"
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
;
48 struct gmsa_update
*gmsa_update
= NULL
;
49 struct gmsa_return_pwd return_pwd
;
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");
68 /* Is the account a Group Managed Service Account? */
69 const bool is_gmsa
= dsdb_account_is_gmsa(ldb
, msg
);
71 /* It’s not a GMSA — we’re done here. */
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");
88 /* TODO: forward the request to a writable DC. */
91 LDB_ERR_OPERATIONS_ERROR
,
92 "msDS-ManagedPassword may only be viewed on a "
93 "writeable DC, not an RODC");
98 tmp_ctx
= talloc_new(msg
);
99 if (tmp_ctx
== NULL
) {
105 struct dom_sid account_sid
;
106 bool allowed_to_view
= false;
108 ret
= samdb_result_dom_sid_buf(msg
, "objectSid", &account_sid
);
113 ret
= gmsa_allowed_to_view_managed_password(
114 tmp_ctx
, ldb
, msg
, &account_sid
, &allowed_to_view
);
119 if (!allowed_to_view
) {
120 /* Sorry, you can’t view the password. */
125 ok
= dsdb_gmsa_current_time(ldb
, ¤t_time
);
127 ret
= ldb_operr(ldb
);
131 ret
= gmsa_recalculate_managed_pwd(
132 tmp_ctx
, ldb
, msg
, current_time
, &gmsa_update
, &return_pwd
);
137 SMB_ASSERT(return_pwd
.new_pwd
!= NULL
);
140 DATA_BLOB packed_blob
= {};
142 status
= gmsa_pack_managed_pwd(
144 return_pwd
.new_pwd
->buf
,
145 return_pwd
.prev_pwd
!= NULL
? return_pwd
.prev_pwd
->buf
147 return_pwd
.query_interval
,
148 return_pwd
.unchanged_interval
,
150 if (!NT_STATUS_IS_OK(status
)) {
151 ret
= ldb_operr(ldb
);
155 ret
= ldb_msg_add_steal_value(msg
,
156 "msDS-ManagedPassword",
164 TALLOC_FREE(tmp_ctx
);
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
),