Line data Source code
1 : /*
2 : ldb database module
3 :
4 : Copyright (C) Simo Sorce 2004-2008
5 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2006
6 : Copyright (C) Andrew Tridgell 2004
7 : Copyright (C) Stefan Metzmacher 2007-2010
8 : Copyright (C) Matthias Dieter Wallnöfer 2009-2010
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : /*
25 : * Name: ldb
26 : *
27 : * Component: ldb password_hash module
28 : *
29 : * Description: correctly handle AD password changes fields
30 : *
31 : * Author: Andrew Bartlett
32 : * Author: Stefan Metzmacher
33 : */
34 :
35 : #include "includes.h"
36 : #include "ldb_errors.h"
37 : #include "ldb_module.h"
38 : #include "libcli/auth/libcli_auth.h"
39 : #include "libcli/security/dom_sid.h"
40 : #include "system/kerberos.h"
41 : #include "auth/kerberos/kerberos.h"
42 : #include "dsdb/gmsa/util.h"
43 : #include "dsdb/samdb/samdb.h"
44 : #include "dsdb/samdb/ldb_modules/util.h"
45 : #include "dsdb/samdb/ldb_modules/password_modules.h"
46 : #include "librpc/gen_ndr/ndr_drsblobs.h"
47 : #include "lib/crypto/md4.h"
48 : #include "param/param.h"
49 : #include "lib/krb5_wrap/krb5_samba.h"
50 : #include "auth/auth_sam.h"
51 : #include "auth/common_auth.h"
52 : #include "lib/messaging/messaging.h"
53 : #include "lib/param/loadparm.h"
54 :
55 : #include "lib/crypto/gnutls_helpers.h"
56 : #include <gnutls/crypto.h>
57 :
58 : #include "kdc/db-glue.h"
59 :
60 : #ifdef ENABLE_GPGME
61 : #undef class
62 : #include <gpgme.h>
63 :
64 : /*
65 : * 1.2.0 is what dpkg-shlibdeps generates, based on used symbols and
66 : * libgpgme11.symbols
67 : * https://salsa.debian.org/debian/gpgme/blob/debian/master/debian/libgpgme11.symbols
68 : */
69 :
70 : #define MINIMUM_GPGME_VERSION "1.2.0"
71 : #endif
72 :
73 : #undef strncasecmp
74 : #undef strcasecmp
75 :
76 : /* If we have decided there is a reason to work on this request, then
77 : * setup all the password hash types correctly.
78 : *
79 : * If we haven't the hashes yet but the password given as plain-text (attributes
80 : * 'unicodePwd', 'userPassword' and 'clearTextPassword') we have to check for
81 : * the constraints. Once this is done, we calculate the password hashes.
82 : *
83 : * Notice: unlike the real AD which only supports the UTF16 special based
84 : * 'unicodePwd' and the UTF8 based 'userPassword' plaintext attribute we
85 : * understand also a UTF16 based 'clearTextPassword' one.
86 : * The latter is also accessible through LDAP so it can also be set by external
87 : * tools and scripts. But be aware that this isn't portable on non SAMBA 4 ADs!
88 : *
89 : * Also when the module receives only the password hashes (possible through
90 : * specifying an internal LDB control - for security reasons) some checks are
91 : * performed depending on the operation mode (see below) (e.g. if the password
92 : * has been in use before if the password memory policy was activated).
93 : *
94 : * Attention: There is a difference between "modify" and "reset" operations
95 : * (see MS-ADTS 3.1.1.3.1.5). If the client sends a "add" and "remove"
96 : * operation for a password attribute we thread this as a "modify"; if it sends
97 : * only a "replace" one we have an (administrative) reset.
98 : *
99 : * Finally, if the administrator has requested that a password history
100 : * be maintained, then this should also be written out.
101 : *
102 : */
103 :
104 : /* TODO: [consider always MS-ADTS 3.1.1.3.1.5]
105 : * - Check for right connection encryption
106 : */
107 :
108 : /* Notice: Definition of "dsdb_control_password_change_status" moved into
109 : * "samdb.h" */
110 :
111 : struct ph_context {
112 : struct ldb_module *module;
113 : struct ldb_request *req;
114 :
115 : struct ldb_request *dom_req;
116 : struct ldb_reply *dom_res;
117 :
118 : struct ldb_reply *pso_res;
119 :
120 : struct ldb_reply *search_res;
121 :
122 : struct ldb_message *update_msg;
123 :
124 : struct dsdb_control_password_change_status *status;
125 : struct dsdb_control_password_change *change;
126 :
127 : const char **gpg_key_ids;
128 :
129 : bool pwd_reset;
130 : bool change_status;
131 : bool hash_values;
132 : bool userPassword;
133 : bool update_password;
134 : bool update_lastset;
135 : bool pwd_last_set_bypass;
136 : bool pwd_last_set_default;
137 : bool smartcard_reset;
138 : const char **userPassword_schemes;
139 : };
140 :
141 :
142 : struct setup_password_fields_io {
143 : struct ph_context *ac;
144 :
145 : struct smb_krb5_context *smb_krb5_context;
146 :
147 : /* info about the user account */
148 : struct {
149 : uint32_t userAccountControl;
150 : NTTIME pwdLastSet;
151 : const char *sAMAccountName;
152 : const char *user_principal_name;
153 : const char *displayName; /* full name */
154 : bool is_krbtgt;
155 : uint32_t restrictions;
156 : struct dom_sid *account_sid;
157 : bool store_nt_hash;
158 : } u;
159 :
160 : /* new credentials and old given credentials */
161 : struct setup_password_fields_given {
162 : const struct ldb_val *cleartext_utf8;
163 : const struct ldb_val *cleartext_utf16;
164 :
165 : struct samr_Password *nt_hash;
166 :
167 : /*
168 : * The AES256 kerberos key to confirm the previous password was
169 : * not reused (for n) and to prove the old password was known
170 : * (for og).
171 : *
172 : * We don't have any old salts, so we won't catch password reuse
173 : * if said password was used prior to an account rename and
174 : * another password change.
175 : */
176 : DATA_BLOB aes_256;
177 : } n, og;
178 :
179 : /* old credentials */
180 : struct {
181 : struct samr_Password *nt_hash;
182 : uint32_t nt_history_len;
183 : struct samr_Password *nt_history;
184 : const struct ldb_val *supplemental;
185 : struct supplementalCredentialsBlob scb;
186 :
187 : /*
188 : * The AES256 kerberos key as stored in the DB.
189 : * Used to confirm the given password was correct
190 : * and in case the previous password was reused.
191 : */
192 : DATA_BLOB aes_256;
193 : DATA_BLOB salt;
194 : uint32_t kvno;
195 : } o;
196 :
197 : /* generated credentials */
198 : struct {
199 : struct samr_Password *nt_hash;
200 : uint32_t nt_history_len;
201 : struct samr_Password *nt_history;
202 : const char *salt;
203 : DATA_BLOB aes_256;
204 : DATA_BLOB aes_128;
205 : DATA_BLOB des_md5;
206 : DATA_BLOB des_crc;
207 : struct ldb_val supplemental;
208 : NTTIME last_set;
209 : } g;
210 : };
211 :
212 : static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
213 : const char *name,
214 : enum ldb_request_type operation,
215 : const struct ldb_val **new_val,
216 : const struct ldb_val **old_val);
217 :
218 23 : static int password_hash_bypass(struct ldb_module *module, struct ldb_request *request)
219 : {
220 23 : struct ldb_context *ldb = ldb_module_get_ctx(module);
221 9 : const struct ldb_message *msg;
222 9 : struct ldb_message_element *nte;
223 9 : struct ldb_message_element *lme;
224 9 : struct ldb_message_element *nthe;
225 9 : struct ldb_message_element *lmhe;
226 9 : struct ldb_message_element *sce;
227 9 : int ret;
228 :
229 23 : switch (request->operation) {
230 0 : case LDB_ADD:
231 0 : msg = request->op.add.message;
232 0 : break;
233 23 : case LDB_MODIFY:
234 23 : msg = request->op.mod.message;
235 23 : break;
236 0 : default:
237 0 : return ldb_next_request(module, request);
238 : }
239 :
240 : /* nobody must touch password histories and 'supplementalCredentials' */
241 :
242 : #define GET_VALUES(el, attr) do { \
243 : ret = dsdb_get_expected_new_values(request, \
244 : msg, \
245 : attr, \
246 : &el, \
247 : request->operation); \
248 : \
249 : if (ret != LDB_SUCCESS) { \
250 : return ret; \
251 : } \
252 : } while(0)
253 :
254 23 : GET_VALUES(nte, "unicodePwd");
255 :
256 : /*
257 : * Even as Samba continues to ignore the LM hash, and reset it
258 : * when practical, we keep the constraint that it must be a 16
259 : * byte value if specified.
260 : */
261 23 : GET_VALUES(lme, "dBCSPwd");
262 23 : GET_VALUES(nthe, "ntPwdHistory");
263 23 : GET_VALUES(lmhe, "lmPwdHistory");
264 23 : GET_VALUES(sce, "supplementalCredentials");
265 :
266 : #undef GET_VALUES
267 : #define CHECK_HASH_ELEMENT(e, min, max) do {\
268 : if (e && e->num_values) { \
269 : unsigned int _count; \
270 : if (e->num_values != 1) { \
271 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
272 : "num_values != 1"); \
273 : } \
274 : if ((e->values[0].length % 16) != 0) { \
275 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
276 : "length % 16 != 0"); \
277 : } \
278 : _count = e->values[0].length / 16; \
279 : if (_count < min) { \
280 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
281 : "count < min"); \
282 : } \
283 : if (_count > max) { \
284 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, \
285 : "count > max"); \
286 : } \
287 : } \
288 : } while (0)
289 :
290 23 : CHECK_HASH_ELEMENT(nte, 1, 1);
291 23 : CHECK_HASH_ELEMENT(lme, 1, 1);
292 23 : CHECK_HASH_ELEMENT(nthe, 1, INT32_MAX);
293 23 : CHECK_HASH_ELEMENT(lmhe, 1, INT32_MAX);
294 :
295 23 : if (sce && sce->num_values) {
296 0 : enum ndr_err_code ndr_err;
297 0 : struct supplementalCredentialsBlob *scb;
298 0 : struct supplementalCredentialsPackage *scpp = NULL;
299 0 : struct supplementalCredentialsPackage *scpk = NULL;
300 0 : struct supplementalCredentialsPackage *scpkn = NULL;
301 0 : struct supplementalCredentialsPackage *scpct = NULL;
302 0 : DATA_BLOB scpbp = data_blob_null;
303 0 : DATA_BLOB scpbk = data_blob_null;
304 0 : DATA_BLOB scpbkn = data_blob_null;
305 0 : DATA_BLOB scpbct = data_blob_null;
306 0 : DATA_BLOB blob;
307 0 : uint32_t i;
308 :
309 0 : if (sce->num_values != 1) {
310 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
311 : "num_values != 1");
312 : }
313 :
314 0 : scb = talloc_zero(request, struct supplementalCredentialsBlob);
315 0 : if (!scb) {
316 0 : return ldb_module_oom(module);
317 : }
318 :
319 0 : ndr_err = ndr_pull_struct_blob_all(&sce->values[0], scb, scb,
320 : (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
321 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
322 0 : talloc_free(scb);
323 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
324 : "ndr_pull_struct_blob_all");
325 : }
326 :
327 0 : if (scb->sub.num_packages < 2) {
328 0 : talloc_free(scb);
329 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
330 : "num_packages < 2");
331 : }
332 :
333 0 : for (i=0; i < scb->sub.num_packages; i++) {
334 0 : DATA_BLOB subblob;
335 :
336 0 : subblob = strhex_to_data_blob(scb, scb->sub.packages[i].data);
337 0 : if (subblob.data == NULL) {
338 0 : talloc_free(scb);
339 0 : return ldb_module_oom(module);
340 : }
341 :
342 0 : if (strcmp(scb->sub.packages[i].name, "Packages") == 0) {
343 0 : if (scpp) {
344 0 : talloc_free(scb);
345 0 : return ldb_error(ldb,
346 : LDB_ERR_CONSTRAINT_VIOLATION,
347 : "Packages twice");
348 : }
349 0 : scpp = &scb->sub.packages[i];
350 0 : scpbp = subblob;
351 0 : continue;
352 : }
353 0 : if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos") == 0) {
354 0 : if (scpk) {
355 0 : talloc_free(scb);
356 0 : return ldb_error(ldb,
357 : LDB_ERR_CONSTRAINT_VIOLATION,
358 : "Primary:Kerberos twice");
359 : }
360 0 : scpk = &scb->sub.packages[i];
361 0 : scpbk = subblob;
362 0 : continue;
363 : }
364 0 : if (strcmp(scb->sub.packages[i].name, "Primary:Kerberos-Newer-Keys") == 0) {
365 0 : if (scpkn) {
366 0 : talloc_free(scb);
367 0 : return ldb_error(ldb,
368 : LDB_ERR_CONSTRAINT_VIOLATION,
369 : "Primary:Kerberos-Newer-Keys twice");
370 : }
371 0 : scpkn = &scb->sub.packages[i];
372 0 : scpbkn = subblob;
373 0 : continue;
374 : }
375 0 : if (strcmp(scb->sub.packages[i].name, "Primary:CLEARTEXT") == 0) {
376 0 : if (scpct) {
377 0 : talloc_free(scb);
378 0 : return ldb_error(ldb,
379 : LDB_ERR_CONSTRAINT_VIOLATION,
380 : "Primary:CLEARTEXT twice");
381 : }
382 0 : scpct = &scb->sub.packages[i];
383 0 : scpbct = subblob;
384 0 : continue;
385 : }
386 :
387 0 : data_blob_free(&subblob);
388 : }
389 :
390 0 : if (scpp == NULL) {
391 0 : talloc_free(scb);
392 0 : return ldb_error(ldb,
393 : LDB_ERR_CONSTRAINT_VIOLATION,
394 : "Primary:Packages missing");
395 : }
396 :
397 0 : if (scpk == NULL) {
398 : /*
399 : * If Primary:Kerberos is missing w2k8r2 reboots
400 : * when a password is changed.
401 : */
402 0 : talloc_free(scb);
403 0 : return ldb_error(ldb,
404 : LDB_ERR_CONSTRAINT_VIOLATION,
405 : "Primary:Kerberos missing");
406 : }
407 :
408 0 : if (scpp) {
409 0 : struct package_PackagesBlob *p;
410 0 : uint32_t n;
411 :
412 0 : p = talloc_zero(scb, struct package_PackagesBlob);
413 0 : if (p == NULL) {
414 0 : talloc_free(scb);
415 0 : return ldb_module_oom(module);
416 : }
417 :
418 0 : ndr_err = ndr_pull_struct_blob(&scpbp, p, p,
419 : (ndr_pull_flags_fn_t)ndr_pull_package_PackagesBlob);
420 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
421 0 : talloc_free(scb);
422 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
423 : "ndr_pull_struct_blob Packages");
424 : }
425 :
426 0 : if (p->names == NULL) {
427 0 : talloc_free(scb);
428 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
429 : "Packages names == NULL");
430 : }
431 :
432 0 : for (n = 0; p->names[n]; n++) {
433 : /* noop */
434 0 : }
435 :
436 0 : if (scb->sub.num_packages != (n + 1)) {
437 0 : talloc_free(scb);
438 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
439 : "Packages num_packages != num_names + 1");
440 : }
441 :
442 0 : talloc_free(p);
443 : }
444 :
445 0 : if (scpk) {
446 0 : struct package_PrimaryKerberosBlob *k;
447 :
448 0 : k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
449 0 : if (k == NULL) {
450 0 : talloc_free(scb);
451 0 : return ldb_module_oom(module);
452 : }
453 :
454 0 : ndr_err = ndr_pull_struct_blob(&scpbk, k, k,
455 : (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
456 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
457 0 : talloc_free(scb);
458 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
459 : "ndr_pull_struct_blob PrimaryKerberos");
460 : }
461 :
462 0 : if (k->version != 3) {
463 0 : talloc_free(scb);
464 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
465 : "PrimaryKerberos version != 3");
466 : }
467 :
468 0 : if (k->ctr.ctr3.salt.string == NULL) {
469 0 : talloc_free(scb);
470 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
471 : "PrimaryKerberos salt == NULL");
472 : }
473 :
474 0 : if (strlen(k->ctr.ctr3.salt.string) == 0) {
475 0 : talloc_free(scb);
476 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
477 : "PrimaryKerberos strlen(salt) == 0");
478 : }
479 :
480 0 : if (k->ctr.ctr3.num_keys != 2) {
481 0 : talloc_free(scb);
482 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
483 : "PrimaryKerberos num_keys != 2");
484 : }
485 :
486 0 : if (k->ctr.ctr3.num_old_keys > k->ctr.ctr3.num_keys) {
487 0 : talloc_free(scb);
488 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
489 : "PrimaryKerberos num_old_keys > num_keys");
490 : }
491 :
492 0 : if (k->ctr.ctr3.keys[0].keytype != ENCTYPE_DES_CBC_MD5) {
493 0 : talloc_free(scb);
494 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
495 : "PrimaryKerberos key[0] != DES_CBC_MD5");
496 : }
497 0 : if (k->ctr.ctr3.keys[1].keytype != ENCTYPE_DES_CBC_CRC) {
498 0 : talloc_free(scb);
499 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
500 : "PrimaryKerberos key[1] != DES_CBC_CRC");
501 : }
502 :
503 0 : if (k->ctr.ctr3.keys[0].value_len != 8) {
504 0 : talloc_free(scb);
505 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
506 : "PrimaryKerberos key[0] value_len != 8");
507 : }
508 0 : if (k->ctr.ctr3.keys[1].value_len != 8) {
509 0 : talloc_free(scb);
510 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
511 : "PrimaryKerberos key[1] value_len != 8");
512 : }
513 :
514 0 : for (i = 0; i < k->ctr.ctr3.num_old_keys; i++) {
515 0 : if (k->ctr.ctr3.old_keys[i].keytype ==
516 0 : k->ctr.ctr3.keys[i].keytype &&
517 0 : k->ctr.ctr3.old_keys[i].value_len ==
518 0 : k->ctr.ctr3.keys[i].value_len) {
519 0 : continue;
520 : }
521 :
522 0 : talloc_free(scb);
523 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
524 : "PrimaryKerberos old_keys type/value_len doesn't match");
525 : }
526 :
527 0 : talloc_free(k);
528 : }
529 :
530 0 : if (scpkn) {
531 0 : struct package_PrimaryKerberosBlob *k;
532 :
533 0 : k = talloc_zero(scb, struct package_PrimaryKerberosBlob);
534 0 : if (k == NULL) {
535 0 : talloc_free(scb);
536 0 : return ldb_module_oom(module);
537 : }
538 :
539 0 : ndr_err = ndr_pull_struct_blob(&scpbkn, k, k,
540 : (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
541 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
542 0 : talloc_free(scb);
543 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
544 : "ndr_pull_struct_blob PrimaryKerberosNewerKeys");
545 : }
546 :
547 0 : if (k->version != 4) {
548 0 : talloc_free(scb);
549 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
550 : "KerberosNewerKeys version != 4");
551 : }
552 :
553 0 : if (k->ctr.ctr4.salt.string == NULL) {
554 0 : talloc_free(scb);
555 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
556 : "KerberosNewerKeys salt == NULL");
557 : }
558 :
559 0 : if (strlen(k->ctr.ctr4.salt.string) == 0) {
560 0 : talloc_free(scb);
561 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
562 : "KerberosNewerKeys strlen(salt) == 0");
563 : }
564 :
565 0 : if (k->ctr.ctr4.num_keys != 4) {
566 0 : talloc_free(scb);
567 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
568 : "KerberosNewerKeys num_keys != 4");
569 : }
570 :
571 0 : if (k->ctr.ctr4.num_old_keys > k->ctr.ctr4.num_keys) {
572 0 : talloc_free(scb);
573 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
574 : "KerberosNewerKeys num_old_keys > num_keys");
575 : }
576 :
577 0 : if (k->ctr.ctr4.num_older_keys > k->ctr.ctr4.num_old_keys) {
578 0 : talloc_free(scb);
579 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
580 : "KerberosNewerKeys num_older_keys > num_old_keys");
581 : }
582 :
583 0 : if (k->ctr.ctr4.keys[0].keytype != ENCTYPE_AES256_CTS_HMAC_SHA1_96) {
584 0 : talloc_free(scb);
585 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
586 : "KerberosNewerKeys key[0] != AES256");
587 : }
588 0 : if (k->ctr.ctr4.keys[1].keytype != ENCTYPE_AES128_CTS_HMAC_SHA1_96) {
589 0 : talloc_free(scb);
590 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
591 : "KerberosNewerKeys key[1] != AES128");
592 : }
593 0 : if (k->ctr.ctr4.keys[2].keytype != ENCTYPE_DES_CBC_MD5) {
594 0 : talloc_free(scb);
595 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
596 : "KerberosNewerKeys key[2] != DES_CBC_MD5");
597 : }
598 0 : if (k->ctr.ctr4.keys[3].keytype != ENCTYPE_DES_CBC_CRC) {
599 0 : talloc_free(scb);
600 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
601 : "KerberosNewerKeys key[3] != DES_CBC_CRC");
602 : }
603 :
604 0 : if (k->ctr.ctr4.keys[0].value_len != 32) {
605 0 : talloc_free(scb);
606 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
607 : "KerberosNewerKeys key[0] value_len != 32");
608 : }
609 0 : if (k->ctr.ctr4.keys[1].value_len != 16) {
610 0 : talloc_free(scb);
611 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
612 : "KerberosNewerKeys key[1] value_len != 16");
613 : }
614 0 : if (k->ctr.ctr4.keys[2].value_len != 8) {
615 0 : talloc_free(scb);
616 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
617 : "KerberosNewerKeys key[2] value_len != 8");
618 : }
619 0 : if (k->ctr.ctr4.keys[3].value_len != 8) {
620 0 : talloc_free(scb);
621 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
622 : "KerberosNewerKeys key[3] value_len != 8");
623 : }
624 :
625 : /*
626 : * TODO:
627 : * Maybe we can check old and older keys here.
628 : * But we need to do some tests, if the old keys
629 : * can be taken from the PrimaryKerberos blob
630 : * (with only des keys), when the domain was upgraded
631 : * from w2k3 to w2k8.
632 : */
633 :
634 0 : talloc_free(k);
635 : }
636 :
637 0 : if (scpct) {
638 0 : struct package_PrimaryCLEARTEXTBlob *ct;
639 :
640 0 : ct = talloc_zero(scb, struct package_PrimaryCLEARTEXTBlob);
641 0 : if (ct == NULL) {
642 0 : talloc_free(scb);
643 0 : return ldb_module_oom(module);
644 : }
645 :
646 0 : ndr_err = ndr_pull_struct_blob(&scpbct, ct, ct,
647 : (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryCLEARTEXTBlob);
648 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
649 0 : talloc_free(scb);
650 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
651 : "ndr_pull_struct_blob PrimaryCLEARTEXT");
652 : }
653 :
654 0 : if ((ct->cleartext.length % 2) != 0) {
655 0 : talloc_free(scb);
656 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
657 : "PrimaryCLEARTEXT length % 2 != 0");
658 : }
659 :
660 0 : talloc_free(ct);
661 : }
662 :
663 0 : ndr_err = ndr_push_struct_blob(&blob, scb, scb,
664 : (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
665 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
666 0 : talloc_free(scb);
667 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
668 : "ndr_push_struct_blob");
669 : }
670 :
671 0 : if (sce->values[0].length != blob.length) {
672 0 : talloc_free(scb);
673 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
674 : "supplementalCredentialsBlob length differ");
675 : }
676 :
677 0 : if (!mem_equal_const_time(sce->values[0].data, blob.data, blob.length)) {
678 0 : talloc_free(scb);
679 0 : return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION,
680 : "supplementalCredentialsBlob memcmp differ");
681 : }
682 :
683 0 : talloc_free(scb);
684 : }
685 :
686 23 : ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_bypass - validated\n");
687 23 : return ldb_next_request(module, request);
688 : }
689 :
690 : /* Get the NT hash, and fill it in as an entry in the password history,
691 : and specify it into io->g.nt_hash */
692 :
693 21905 : static int setup_nt_fields(struct setup_password_fields_io *io)
694 : {
695 21905 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
696 205 : uint32_t i;
697 21905 : if (io->u.store_nt_hash) {
698 20993 : io->g.nt_hash = io->n.nt_hash;
699 : }
700 :
701 21905 : if (io->ac->status->domain_data.pwdHistoryLength == 0) {
702 50 : return LDB_SUCCESS;
703 : }
704 :
705 : /* We might not have an old NT password */
706 :
707 21855 : if (io->g.nt_hash == NULL) {
708 : /*
709 : * If there was not an NT hash specified, then don't
710 : * store the NT password history.
711 : *
712 : * While the NTLM code on a Windows DC will cope with
713 : * a missing unicodePwd, if it finds a last password
714 : * in the ntPwdHistory, even if the bytes are zero ,
715 : * it will (quite reasonably) treat it as a valid NT
716 : * hash. NTLM logins with the previous password are
717 : * allowed for a short time after the password is
718 : * changed to allow for password propagation delays.
719 : */
720 912 : return LDB_SUCCESS;
721 : }
722 :
723 20943 : io->g.nt_history = talloc_array(io->ac,
724 : struct samr_Password,
725 : io->ac->status->domain_data.pwdHistoryLength);
726 20943 : if (!io->g.nt_history) {
727 0 : return ldb_oom(ldb);
728 : }
729 :
730 36777 : for (i = 0; i < MIN(io->ac->status->domain_data.pwdHistoryLength-1,
731 15834 : io->o.nt_history_len); i++) {
732 15834 : io->g.nt_history[i+1] = io->o.nt_history[i];
733 : }
734 20943 : io->g.nt_history_len = i + 1;
735 :
736 20943 : io->g.nt_history[0] = *io->g.nt_hash;
737 :
738 20943 : return LDB_SUCCESS;
739 : }
740 :
741 21547 : static int setup_kerberos_keys(struct setup_password_fields_io *io)
742 : {
743 199 : struct ldb_context *ldb;
744 199 : krb5_error_code krb5_ret;
745 21547 : krb5_principal salt_principal = NULL;
746 199 : krb5_data salt_data;
747 199 : krb5_data salt;
748 199 : krb5_keyblock key;
749 199 : krb5_data cleartext_data;
750 21547 : uint32_t uac_flags = 0;
751 :
752 21547 : ldb = ldb_module_get_ctx(io->ac->module);
753 21547 : cleartext_data.data = (char *)io->n.cleartext_utf8->data;
754 21547 : cleartext_data.length = io->n.cleartext_utf8->length;
755 :
756 21547 : uac_flags = io->u.userAccountControl & UF_ACCOUNT_TYPE_MASK;
757 21746 : krb5_ret = smb_krb5_salt_principal(io->smb_krb5_context->krb5_context,
758 21547 : io->ac->status->domain_data.realm,
759 : io->u.sAMAccountName,
760 : io->u.user_principal_name,
761 : uac_flags,
762 : &salt_principal);
763 21547 : if (krb5_ret) {
764 2 : ldb_asprintf_errstring(ldb,
765 : "setup_kerberos_keys: "
766 : "generation of a salting principal failed: %s",
767 2 : smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
768 2 : krb5_ret, io->ac));
769 2 : return LDB_ERR_OPERATIONS_ERROR;
770 : }
771 :
772 : /*
773 : * create salt from salt_principal
774 : */
775 21545 : krb5_ret = smb_krb5_get_pw_salt(io->smb_krb5_context->krb5_context,
776 : salt_principal, &salt_data);
777 :
778 21545 : krb5_free_principal(io->smb_krb5_context->krb5_context, salt_principal);
779 21545 : if (krb5_ret) {
780 0 : ldb_asprintf_errstring(ldb,
781 : "setup_kerberos_keys: "
782 : "generation of krb5_salt failed: %s",
783 0 : smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
784 0 : krb5_ret, io->ac));
785 0 : return LDB_ERR_OPERATIONS_ERROR;
786 : }
787 :
788 : /* now use the talloced copy of the salt */
789 43090 : salt.data = talloc_strndup(io->ac,
790 21545 : (char *)salt_data.data,
791 7948 : salt_data.length);
792 21545 : smb_krb5_free_data_contents(io->smb_krb5_context->krb5_context,
793 : &salt_data);
794 21545 : if (salt.data == NULL) {
795 0 : return ldb_oom(ldb);
796 : }
797 21545 : io->g.salt = salt.data;
798 21545 : salt.length = strlen(io->g.salt);
799 :
800 : /*
801 : * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of
802 : * the salt and the cleartext password
803 : */
804 21545 : krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
805 : NULL,
806 : &salt,
807 : &cleartext_data,
808 : ENCTYPE_AES256_CTS_HMAC_SHA1_96,
809 : &key);
810 21545 : if (krb5_ret) {
811 0 : ldb_asprintf_errstring(ldb,
812 : "setup_kerberos_keys: "
813 : "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
814 0 : smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
815 0 : krb5_ret, io->ac));
816 0 : return LDB_ERR_OPERATIONS_ERROR;
817 : }
818 21545 : io->g.aes_256 = data_blob_talloc(io->ac,
819 : KRB5_KEY_DATA(&key),
820 : KRB5_KEY_LENGTH(&key));
821 21545 : krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
822 21545 : if (!io->g.aes_256.data) {
823 0 : return ldb_oom(ldb);
824 : }
825 :
826 : /*
827 : * create ENCTYPE_AES128_CTS_HMAC_SHA1_96 key out of
828 : * the salt and the cleartext password
829 : */
830 21545 : krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
831 : NULL,
832 : &salt,
833 : &cleartext_data,
834 : ENCTYPE_AES128_CTS_HMAC_SHA1_96,
835 : &key);
836 21545 : if (krb5_ret) {
837 0 : ldb_asprintf_errstring(ldb,
838 : "setup_kerberos_keys: "
839 : "generation of a aes128-cts-hmac-sha1-96 key failed: %s",
840 0 : smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
841 0 : krb5_ret, io->ac));
842 0 : return LDB_ERR_OPERATIONS_ERROR;
843 : }
844 21545 : io->g.aes_128 = data_blob_talloc(io->ac,
845 : KRB5_KEY_DATA(&key),
846 : KRB5_KEY_LENGTH(&key));
847 21545 : krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
848 21545 : if (!io->g.aes_128.data) {
849 0 : return ldb_oom(ldb);
850 : }
851 :
852 : /*
853 : * As per RFC-6649 single DES encryption types are no longer considered
854 : * secure to be used in Kerberos, we store random keys instead of the
855 : * ENCTYPE_DES_CBC_MD5 and ENCTYPE_DES_CBC_CRC keys.
856 : */
857 21545 : io->g.des_md5 = data_blob_talloc(io->ac, NULL, 8);
858 21545 : if (!io->g.des_md5.data) {
859 0 : return ldb_oom(ldb);
860 : }
861 21545 : generate_secret_buffer(io->g.des_md5.data, 8);
862 :
863 21545 : io->g.des_crc = data_blob_talloc(io->ac, NULL, 8);
864 21545 : if (!io->g.des_crc.data) {
865 0 : return ldb_oom(ldb);
866 : }
867 21545 : generate_secret_buffer(io->g.des_crc.data, 8);
868 :
869 21545 : return LDB_SUCCESS;
870 : }
871 :
872 22675 : static int setup_kerberos_key_hash(struct setup_password_fields_io *io,
873 : struct setup_password_fields_given *g)
874 : {
875 22675 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
876 199 : krb5_error_code krb5_ret;
877 199 : krb5_data salt;
878 199 : krb5_keyblock key;
879 199 : krb5_data cleartext_data;
880 :
881 22675 : if (io->ac->search_res == NULL) {
882 : /* No old data so nothing to do */
883 3995 : return LDB_SUCCESS;
884 : }
885 :
886 18612 : if (io->o.salt.data == NULL) {
887 : /* We didn't fetch the salt in setup_io(), so nothing to do */
888 15293 : return LDB_SUCCESS;
889 : }
890 :
891 3220 : salt.data = (char *)io->o.salt.data;
892 3220 : salt.length = io->o.salt.length;
893 :
894 3220 : cleartext_data.data = (char *)g->cleartext_utf8->data;
895 3220 : cleartext_data.length = g->cleartext_utf8->length;
896 :
897 : /*
898 : * create ENCTYPE_AES256_CTS_HMAC_SHA1_96 key out of the salt
899 : * and the cleartext password
900 : */
901 3220 : krb5_ret = smb_krb5_create_key_from_string(io->smb_krb5_context->krb5_context,
902 : NULL,
903 : &salt,
904 : &cleartext_data,
905 : ENCTYPE_AES256_CTS_HMAC_SHA1_96,
906 : &key);
907 3220 : if (krb5_ret) {
908 0 : ldb_asprintf_errstring(ldb,
909 : "setup_kerberos_key_hash: "
910 : "generation of a aes256-cts-hmac-sha1-96 key failed: %s",
911 0 : smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
912 0 : krb5_ret, io->ac));
913 0 : return LDB_ERR_OPERATIONS_ERROR;
914 : }
915 :
916 3220 : g->aes_256 = data_blob_talloc(io->ac,
917 : KRB5_KEY_DATA(&key),
918 : KRB5_KEY_LENGTH(&key));
919 3220 : krb5_free_keyblock_contents(io->smb_krb5_context->krb5_context, &key);
920 3220 : if (g->aes_256.data == NULL) {
921 0 : return ldb_oom(ldb);
922 : }
923 :
924 3220 : talloc_keep_secret(g->aes_256.data);
925 :
926 3220 : return LDB_SUCCESS;
927 : }
928 :
929 21545 : static int setup_primary_kerberos(struct setup_password_fields_io *io,
930 : const struct supplementalCredentialsBlob *old_scb,
931 : struct package_PrimaryKerberosBlob *pkb)
932 : {
933 199 : struct ldb_context *ldb;
934 21545 : struct package_PrimaryKerberosCtr3 *pkb3 = &pkb->ctr.ctr3;
935 21545 : struct supplementalCredentialsPackage *old_scp = NULL;
936 199 : struct package_PrimaryKerberosBlob _old_pkb;
937 21545 : struct package_PrimaryKerberosCtr3 *old_pkb3 = NULL;
938 199 : uint32_t i;
939 199 : enum ndr_err_code ndr_err;
940 :
941 21545 : ldb = ldb_module_get_ctx(io->ac->module);
942 :
943 : /*
944 : * prepare generation of keys
945 : *
946 : * ENCTYPE_DES_CBC_MD5
947 : * ENCTYPE_DES_CBC_CRC
948 : */
949 21545 : pkb->version = 3;
950 21545 : pkb3->salt.string = io->g.salt;
951 21545 : pkb3->num_keys = 2;
952 21545 : pkb3->keys = talloc_array(io->ac,
953 : struct package_PrimaryKerberosKey3,
954 : pkb3->num_keys);
955 21545 : if (!pkb3->keys) {
956 0 : return ldb_oom(ldb);
957 : }
958 :
959 21545 : pkb3->keys[0].keytype = ENCTYPE_DES_CBC_MD5;
960 21545 : pkb3->keys[0].value = &io->g.des_md5;
961 21545 : pkb3->keys[1].keytype = ENCTYPE_DES_CBC_CRC;
962 21545 : pkb3->keys[1].value = &io->g.des_crc;
963 :
964 : /* initialize the old keys to zero */
965 21545 : pkb3->num_old_keys = 0;
966 21545 : pkb3->old_keys = NULL;
967 :
968 : /* if there're no old keys, then we're done */
969 21545 : if (!old_scb) {
970 18900 : return LDB_SUCCESS;
971 : }
972 :
973 4860 : for (i=0; i < old_scb->sub.num_packages; i++) {
974 4860 : if (strcmp("Primary:Kerberos", old_scb->sub.packages[i].name) != 0) {
975 2382 : continue;
976 : }
977 :
978 2478 : if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
979 0 : continue;
980 : }
981 :
982 2446 : old_scp = &old_scb->sub.packages[i];
983 2446 : break;
984 : }
985 : /* Primary:Kerberos element of supplementalCredentials */
986 2478 : if (old_scp) {
987 32 : DATA_BLOB blob;
988 :
989 2478 : blob = strhex_to_data_blob(io->ac, old_scp->data);
990 2478 : if (!blob.data) {
991 0 : return ldb_oom(ldb);
992 : }
993 :
994 : /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
995 2478 : ndr_err = ndr_pull_struct_blob(&blob, io->ac, &_old_pkb,
996 : (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
997 2478 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
998 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
999 0 : ldb_asprintf_errstring(ldb,
1000 : "setup_primary_kerberos: "
1001 : "failed to pull old package_PrimaryKerberosBlob: %s",
1002 : nt_errstr(status));
1003 0 : return LDB_ERR_OPERATIONS_ERROR;
1004 : }
1005 :
1006 2478 : if (_old_pkb.version != 3) {
1007 0 : ldb_asprintf_errstring(ldb,
1008 : "setup_primary_kerberos: "
1009 : "package_PrimaryKerberosBlob version[%u] expected[3]",
1010 0 : _old_pkb.version);
1011 0 : return LDB_ERR_OPERATIONS_ERROR;
1012 : }
1013 :
1014 2478 : old_pkb3 = &_old_pkb.ctr.ctr3;
1015 : }
1016 :
1017 : /* if we didn't find the old keys we're done */
1018 2478 : if (!old_pkb3) {
1019 0 : return LDB_SUCCESS;
1020 : }
1021 :
1022 : /* fill in the old keys */
1023 2478 : pkb3->num_old_keys = old_pkb3->num_keys;
1024 2478 : pkb3->old_keys = old_pkb3->keys;
1025 :
1026 2478 : return LDB_SUCCESS;
1027 : }
1028 :
1029 16536 : static int setup_primary_kerberos_newer(struct setup_password_fields_io *io,
1030 : const struct supplementalCredentialsBlob *old_scb,
1031 : struct package_PrimaryKerberosBlob *pkb)
1032 : {
1033 189 : struct ldb_context *ldb;
1034 16536 : struct package_PrimaryKerberosCtr4 *pkb4 = &pkb->ctr.ctr4;
1035 16536 : struct supplementalCredentialsPackage *old_scp = NULL;
1036 189 : struct package_PrimaryKerberosBlob _old_pkb;
1037 16536 : struct package_PrimaryKerberosCtr4 *old_pkb4 = NULL;
1038 189 : uint32_t i;
1039 189 : enum ndr_err_code ndr_err;
1040 :
1041 16536 : ldb = ldb_module_get_ctx(io->ac->module);
1042 :
1043 : /*
1044 : * prepare generation of keys
1045 : *
1046 : * ENCTYPE_AES256_CTS_HMAC_SHA1_96
1047 : * ENCTYPE_AES128_CTS_HMAC_SHA1_96
1048 : * ENCTYPE_DES_CBC_MD5
1049 : * ENCTYPE_DES_CBC_CRC
1050 : */
1051 16536 : pkb->version = 4;
1052 16536 : pkb4->salt.string = io->g.salt;
1053 16536 : pkb4->default_iteration_count = 4096;
1054 16536 : pkb4->num_keys = 4;
1055 :
1056 16536 : pkb4->keys = talloc_array(io->ac,
1057 : struct package_PrimaryKerberosKey4,
1058 : pkb4->num_keys);
1059 16536 : if (!pkb4->keys) {
1060 0 : return ldb_oom(ldb);
1061 : }
1062 :
1063 16536 : pkb4->keys[0].iteration_count = 4096;
1064 16536 : pkb4->keys[0].keytype = ENCTYPE_AES256_CTS_HMAC_SHA1_96;
1065 16536 : pkb4->keys[0].value = &io->g.aes_256;
1066 16536 : pkb4->keys[1].iteration_count = 4096;
1067 16536 : pkb4->keys[1].keytype = ENCTYPE_AES128_CTS_HMAC_SHA1_96;
1068 16536 : pkb4->keys[1].value = &io->g.aes_128;
1069 16536 : pkb4->keys[2].iteration_count = 4096;
1070 16536 : pkb4->keys[2].keytype = ENCTYPE_DES_CBC_MD5;
1071 16536 : pkb4->keys[2].value = &io->g.des_md5;
1072 16536 : pkb4->keys[3].iteration_count = 4096;
1073 16536 : pkb4->keys[3].keytype = ENCTYPE_DES_CBC_CRC;
1074 16536 : pkb4->keys[3].value = &io->g.des_crc;
1075 :
1076 : /* initialize the old keys to zero */
1077 16536 : pkb4->num_old_keys = 0;
1078 16536 : pkb4->old_keys = NULL;
1079 16536 : pkb4->num_older_keys = 0;
1080 16536 : pkb4->older_keys = NULL;
1081 :
1082 : /* if there're no old keys, then we're done */
1083 16536 : if (!old_scb) {
1084 13997 : return LDB_SUCCESS;
1085 : }
1086 :
1087 2382 : for (i=0; i < old_scb->sub.num_packages; i++) {
1088 2382 : if (strcmp("Primary:Kerberos-Newer-Keys", old_scb->sub.packages[i].name) != 0) {
1089 0 : continue;
1090 : }
1091 :
1092 2382 : if (!old_scb->sub.packages[i].data || !old_scb->sub.packages[i].data[0]) {
1093 0 : continue;
1094 : }
1095 :
1096 2350 : old_scp = &old_scb->sub.packages[i];
1097 2350 : break;
1098 : }
1099 : /* Primary:Kerberos-Newer-Keys element of supplementalCredentials */
1100 2382 : if (old_scp) {
1101 32 : DATA_BLOB blob;
1102 :
1103 2382 : blob = strhex_to_data_blob(io->ac, old_scp->data);
1104 2382 : if (!blob.data) {
1105 0 : return ldb_oom(ldb);
1106 : }
1107 :
1108 : /* TODO: use ndr_pull_struct_blob_all(), when the ndr layer handles it correct with relative pointers */
1109 2382 : ndr_err = ndr_pull_struct_blob(&blob, io->ac,
1110 : &_old_pkb,
1111 : (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
1112 2382 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
1113 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
1114 0 : ldb_asprintf_errstring(ldb,
1115 : "setup_primary_kerberos_newer: "
1116 : "failed to pull old package_PrimaryKerberosBlob: %s",
1117 : nt_errstr(status));
1118 0 : return LDB_ERR_OPERATIONS_ERROR;
1119 : }
1120 :
1121 2382 : if (_old_pkb.version != 4) {
1122 0 : ldb_asprintf_errstring(ldb,
1123 : "setup_primary_kerberos_newer: "
1124 : "package_PrimaryKerberosBlob version[%u] expected[4]",
1125 0 : _old_pkb.version);
1126 0 : return LDB_ERR_OPERATIONS_ERROR;
1127 : }
1128 :
1129 2382 : old_pkb4 = &_old_pkb.ctr.ctr4;
1130 : }
1131 :
1132 : /* if we didn't find the old keys we're done */
1133 2382 : if (!old_pkb4) {
1134 0 : return LDB_SUCCESS;
1135 : }
1136 :
1137 : /* fill in the old keys */
1138 2382 : pkb4->num_old_keys = old_pkb4->num_keys;
1139 2382 : pkb4->old_keys = old_pkb4->keys;
1140 2382 : pkb4->num_older_keys = old_pkb4->num_old_keys;
1141 2382 : pkb4->older_keys = old_pkb4->old_keys;
1142 :
1143 2382 : return LDB_SUCCESS;
1144 : }
1145 :
1146 21545 : static int setup_primary_wdigest(struct setup_password_fields_io *io,
1147 : const struct supplementalCredentialsBlob *old_scb,
1148 : struct package_PrimaryWDigestBlob *pdb)
1149 : {
1150 21545 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1151 199 : DATA_BLOB sAMAccountName;
1152 199 : DATA_BLOB sAMAccountName_l;
1153 199 : DATA_BLOB sAMAccountName_u;
1154 21545 : const char *user_principal_name = io->u.user_principal_name;
1155 199 : DATA_BLOB userPrincipalName;
1156 199 : DATA_BLOB userPrincipalName_l;
1157 199 : DATA_BLOB userPrincipalName_u;
1158 199 : DATA_BLOB netbios_domain;
1159 199 : DATA_BLOB netbios_domain_l;
1160 199 : DATA_BLOB netbios_domain_u;
1161 199 : DATA_BLOB dns_domain;
1162 199 : DATA_BLOB dns_domain_l;
1163 199 : DATA_BLOB dns_domain_u;
1164 199 : DATA_BLOB digest;
1165 199 : DATA_BLOB delim;
1166 199 : DATA_BLOB backslash;
1167 199 : uint8_t i;
1168 199 : struct {
1169 : DATA_BLOB *user;
1170 : DATA_BLOB *realm;
1171 : DATA_BLOB *nt4dom;
1172 21545 : } wdigest[] = {
1173 : /*
1174 : * See 3.1.1.8.11.3.1 WDIGEST_CREDENTIALS Construction
1175 : * https://msdn.microsoft.com/en-us/library/cc245680.aspx
1176 : * for what precalculated hashes are supposed to be stored...
1177 : *
1178 : * I can't reproduce all values which should contain "Digest" as realm,
1179 : * am I doing something wrong or is w2k3 just broken...?
1180 : *
1181 : * W2K3 fills in following for a user:
1182 : *
1183 : * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1184 : * sAMAccountName: NewUser2Sam
1185 : * userPrincipalName: NewUser2Princ@sub1.w2k3.vmnet1.vm.base
1186 : *
1187 : * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1188 : * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1189 : * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1190 : * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1191 : * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1192 : * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1193 : * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1194 : * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1195 : * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1196 : * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1197 : * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1198 : * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1199 : * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1200 : * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1201 : * 221c55284451ae9b3aacaa2a3c86f10f => NewUser2Princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1202 : * 74e1be668853d4324d38c07e2acfb8ea => (w2k3 has a bug here!) newuser2princ@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1203 : * e1e244ab7f098e3ae1761be7f9229bbb => NEWUSER2PRINC@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1204 : * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1205 : * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1206 : * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1207 : * 31dc704d3640335b2123d4ee28aa1f11 => ??? changes with NewUser2Sam => NewUser1Sam
1208 : * 36349f5cecd07320fb3bb0e119230c43 => ??? changes with NewUser2Sam => NewUser1Sam
1209 : * 12adf019d037fb535c01fd0608e78d9d => ??? changes with NewUser2Sam => NewUser1Sam
1210 : * 6feecf8e724906f3ee1105819c5105a1 => ??? changes with NewUser2Princ => NewUser1Princ
1211 : * 6c6911f3de6333422640221b9c51ff1f => ??? changes with NewUser2Princ => NewUser1Princ
1212 : * 4b279877e742895f9348ac67a8de2f69 => ??? changes with NewUser2Princ => NewUser1Princ
1213 : * db0c6bff069513e3ebb9870d29b57490 => ??? changes with NewUser2Sam => NewUser1Sam
1214 : * 45072621e56b1c113a4e04a8ff68cd0e => ??? changes with NewUser2Sam => NewUser1Sam
1215 : * 11d1220abc44a9c10cf91ef4a9c1de02 => ??? changes with NewUser2Sam => NewUser1Sam
1216 : *
1217 : * dn: CN=NewUser,OU=newtop,DC=sub1,DC=w2k3,DC=vmnet1,DC=vm,DC=base
1218 : * sAMAccountName: NewUser2Sam
1219 : *
1220 : * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1221 : * b7ec9da91062199aee7d121e6710fe23 => newuser2sam:sub1:TestPwd2007
1222 : * 17d290bc5c9f463fac54c37a8cea134d => NEWUSER2SAM:SUB1:TestPwd2007
1223 : * 4279815024bda54fc074a5f8bd0a6e6f => NewUser2Sam:SUB1:TestPwd2007
1224 : * 5d57e7823938348127322e08cd81bcb5 => NewUser2Sam:sub1:TestPwd2007
1225 : * 07dd701bf8a011ece585de3d47237140 => NEWUSER2SAM:sub1:TestPwd2007
1226 : * e14fb0eb401498d2cb33c9aae1cc7f37 => newuser2sam:SUB1:TestPwd2007
1227 : * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1228 : * f52da1266a6bdd290ffd48b2c823dda7 => newuser2sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1229 : * d2b42f171248cec37a3c5c6b55404062 => NEWUSER2SAM:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1230 : * fff8d790ff6c152aaeb6ebe17b4021de => NewUser2Sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1231 : * 8dadc90250f873d8b883f79d890bef82 => NewUser2Sam:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1232 : * 2a7563c3715bc418d626dabef378c008 => NEWUSER2SAM:sub1.w2k3.vmnet1.vm.base:TestPwd2007
1233 : * c8e9557a87cd4200fda0c11d2fa03f96 => newuser2sam:SUB1.W2K3.VMNET1.VM.BASE:TestPwd2007
1234 : * 8a140d30b6f0a5912735dc1e3bc993b4 => NewUser2Sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1235 : * 86d95b2faae6cae4ec261e7fbaccf093 => (here w2k3 is correct) newuser2sam@sub1.w2k3.vmnet1.vm.base::TestPwd2007
1236 : * dfeff1493110220efcdfc6362e5f5450 => NEWUSER2SAM@SUB1.W2K3.VMNET1.VM.BASE::TestPwd2007
1237 : * 86db637df42513039920e605499c3af6 => SUB1\NewUser2Sam::TestPwd2007
1238 : * f5e43474dfaf067fee8197a253debaa2 => sub1\newuser2sam::TestPwd2007
1239 : * 2ecaa8382e2518e4b77a52422b279467 => SUB1\NEWUSER2SAM::TestPwd2007
1240 : * 31dc704d3640335b2123d4ee28aa1f11 => ???M1 changes with NewUser2Sam => NewUser1Sam
1241 : * 36349f5cecd07320fb3bb0e119230c43 => ???M1.L changes with newuser2sam => newuser1sam
1242 : * 12adf019d037fb535c01fd0608e78d9d => ???M1.U changes with NEWUSER2SAM => NEWUSER1SAM
1243 : * 569b4533f2d9e580211dd040e5e360a8 => ???M2 changes with NewUser2Princ => NewUser1Princ
1244 : * 52528bddf310a587c5d7e6a9ae2cbb20 => ???M2.L changes with newuser2princ => newuser1princ
1245 : * 4f629a4f0361289ca4255ab0f658fcd5 => ???M3 changes with NewUser2Princ => NewUser1Princ (doesn't depend on case of userPrincipal )
1246 : * db0c6bff069513e3ebb9870d29b57490 => ???M4 changes with NewUser2Sam => NewUser1Sam
1247 : * 45072621e56b1c113a4e04a8ff68cd0e => ???M5 changes with NewUser2Sam => NewUser1Sam (doesn't depend on case of sAMAccountName)
1248 : * 11d1220abc44a9c10cf91ef4a9c1de02 => ???M4.U changes with NEWUSER2SAM => NEWUSER1SAM
1249 : */
1250 :
1251 : /*
1252 : * sAMAccountName, netbios_domain
1253 : */
1254 : {
1255 : .user = &sAMAccountName,
1256 : .realm = &netbios_domain,
1257 : },
1258 : {
1259 : .user = &sAMAccountName_l,
1260 : .realm = &netbios_domain_l,
1261 : },
1262 : {
1263 : .user = &sAMAccountName_u,
1264 : .realm = &netbios_domain_u,
1265 : },
1266 : {
1267 : .user = &sAMAccountName,
1268 : .realm = &netbios_domain_u,
1269 : },
1270 : {
1271 : .user = &sAMAccountName,
1272 : .realm = &netbios_domain_l,
1273 : },
1274 : {
1275 : .user = &sAMAccountName_u,
1276 : .realm = &netbios_domain_l,
1277 : },
1278 : {
1279 : .user = &sAMAccountName_l,
1280 : .realm = &netbios_domain_u,
1281 : },
1282 : /*
1283 : * sAMAccountName, dns_domain
1284 : *
1285 : * TODO:
1286 : * Windows preserves the case of the DNS domain,
1287 : * Samba lower cases the domain at provision time
1288 : * This means that for mixed case Domains, the WDigest08 hash
1289 : * calculated by Samba differs from that calculated by Windows.
1290 : * Until we get a real world use case this will remain a known
1291 : * bug, as changing the case could have unforeseen impacts.
1292 : *
1293 : */
1294 : {
1295 : .user = &sAMAccountName,
1296 : .realm = &dns_domain,
1297 : },
1298 : {
1299 : .user = &sAMAccountName_l,
1300 : .realm = &dns_domain_l,
1301 : },
1302 : {
1303 : .user = &sAMAccountName_u,
1304 : .realm = &dns_domain_u,
1305 : },
1306 : {
1307 : .user = &sAMAccountName,
1308 : .realm = &dns_domain_u,
1309 : },
1310 : {
1311 : .user = &sAMAccountName,
1312 : .realm = &dns_domain_l,
1313 : },
1314 : {
1315 : .user = &sAMAccountName_u,
1316 : .realm = &dns_domain_l,
1317 : },
1318 : {
1319 : .user = &sAMAccountName_l,
1320 : .realm = &dns_domain_u,
1321 : },
1322 : /*
1323 : * userPrincipalName, no realm
1324 : */
1325 : {
1326 : .user = &userPrincipalName,
1327 : },
1328 : {
1329 : /*
1330 : * NOTE: w2k3 messes this up, if the user has a real userPrincipalName,
1331 : * the fallback to the sAMAccountName based userPrincipalName is correct
1332 : */
1333 : .user = &userPrincipalName_l,
1334 : },
1335 : {
1336 : .user = &userPrincipalName_u,
1337 : },
1338 : /*
1339 : * nt4dom\sAMAccountName, no realm
1340 : */
1341 : {
1342 : .user = &sAMAccountName,
1343 : .nt4dom = &netbios_domain
1344 : },
1345 : {
1346 : .user = &sAMAccountName_l,
1347 : .nt4dom = &netbios_domain_l
1348 : },
1349 : {
1350 : .user = &sAMAccountName_u,
1351 : .nt4dom = &netbios_domain_u
1352 : },
1353 :
1354 : /*
1355 : * the following ones are guessed depending on the technet2 article
1356 : * but not reproducible on a w2k3 server
1357 : */
1358 : /* sAMAccountName with "Digest" realm */
1359 : {
1360 : .user = &sAMAccountName,
1361 : .realm = &digest
1362 : },
1363 : {
1364 : .user = &sAMAccountName_l,
1365 : .realm = &digest
1366 : },
1367 : {
1368 : .user = &sAMAccountName_u,
1369 : .realm = &digest
1370 : },
1371 : /* userPrincipalName with "Digest" realm */
1372 : {
1373 : .user = &userPrincipalName,
1374 : .realm = &digest
1375 : },
1376 : {
1377 : .user = &userPrincipalName_l,
1378 : .realm = &digest
1379 : },
1380 : {
1381 : .user = &userPrincipalName_u,
1382 : .realm = &digest
1383 : },
1384 : /* nt4dom\\sAMAccountName with "Digest" realm */
1385 : {
1386 : .user = &sAMAccountName,
1387 : .nt4dom = &netbios_domain,
1388 : .realm = &digest
1389 : },
1390 : {
1391 : .user = &sAMAccountName_l,
1392 : .nt4dom = &netbios_domain_l,
1393 : .realm = &digest
1394 : },
1395 : {
1396 : .user = &sAMAccountName_u,
1397 : .nt4dom = &netbios_domain_u,
1398 : .realm = &digest
1399 : },
1400 : };
1401 21545 : int rc = LDB_ERR_OTHER;
1402 :
1403 : /* prepare DATA_BLOB's used in the combinations array */
1404 21545 : sAMAccountName = data_blob_string_const(io->u.sAMAccountName);
1405 21545 : sAMAccountName_l = data_blob_string_const(strlower_talloc(io->ac, io->u.sAMAccountName));
1406 21545 : if (!sAMAccountName_l.data) {
1407 0 : return ldb_oom(ldb);
1408 : }
1409 21545 : sAMAccountName_u = data_blob_string_const(strupper_talloc(io->ac, io->u.sAMAccountName));
1410 21545 : if (!sAMAccountName_u.data) {
1411 0 : return ldb_oom(ldb);
1412 : }
1413 :
1414 : /* if the user doesn't have a userPrincipalName, create one (with lower case realm) */
1415 21545 : if (!user_principal_name) {
1416 7347 : user_principal_name = talloc_asprintf(io->ac, "%s@%s",
1417 : io->u.sAMAccountName,
1418 7180 : io->ac->status->domain_data.dns_domain);
1419 7180 : if (!user_principal_name) {
1420 0 : return ldb_oom(ldb);
1421 : }
1422 : }
1423 21545 : userPrincipalName = data_blob_string_const(user_principal_name);
1424 21545 : userPrincipalName_l = data_blob_string_const(strlower_talloc(io->ac, user_principal_name));
1425 21545 : if (!userPrincipalName_l.data) {
1426 0 : return ldb_oom(ldb);
1427 : }
1428 21545 : userPrincipalName_u = data_blob_string_const(strupper_talloc(io->ac, user_principal_name));
1429 21545 : if (!userPrincipalName_u.data) {
1430 0 : return ldb_oom(ldb);
1431 : }
1432 :
1433 21545 : netbios_domain = data_blob_string_const(io->ac->status->domain_data.netbios_domain);
1434 21545 : netbios_domain_l = data_blob_string_const(strlower_talloc(io->ac,
1435 21545 : io->ac->status->domain_data.netbios_domain));
1436 21545 : if (!netbios_domain_l.data) {
1437 0 : return ldb_oom(ldb);
1438 : }
1439 21545 : netbios_domain_u = data_blob_string_const(strupper_talloc(io->ac,
1440 21545 : io->ac->status->domain_data.netbios_domain));
1441 21545 : if (!netbios_domain_u.data) {
1442 0 : return ldb_oom(ldb);
1443 : }
1444 :
1445 21545 : dns_domain = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1446 21545 : dns_domain_l = data_blob_string_const(io->ac->status->domain_data.dns_domain);
1447 21545 : dns_domain_u = data_blob_string_const(io->ac->status->domain_data.realm);
1448 :
1449 21545 : digest = data_blob_string_const("Digest");
1450 :
1451 21545 : delim = data_blob_string_const(":");
1452 21545 : backslash = data_blob_string_const("\\");
1453 :
1454 21545 : pdb->num_hashes = ARRAY_SIZE(wdigest);
1455 21545 : pdb->hashes = talloc_array(io->ac, struct package_PrimaryWDigestHash,
1456 : pdb->num_hashes);
1457 21545 : if (!pdb->hashes) {
1458 0 : return ldb_oom(ldb);
1459 : }
1460 :
1461 646350 : for (i=0; i < ARRAY_SIZE(wdigest); i++) {
1462 624805 : gnutls_hash_hd_t hash_hnd = NULL;
1463 :
1464 624805 : rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
1465 624805 : if (rc < 0) {
1466 0 : rc = ldb_oom(ldb);
1467 0 : goto out;
1468 : }
1469 :
1470 624805 : if (wdigest[i].nt4dom) {
1471 130464 : rc = gnutls_hash(hash_hnd,
1472 129270 : wdigest[i].nt4dom->data,
1473 128076 : wdigest[i].nt4dom->length);
1474 129270 : if (rc < 0) {
1475 0 : gnutls_hash_deinit(hash_hnd, NULL);
1476 0 : rc = LDB_ERR_UNWILLING_TO_PERFORM;
1477 0 : goto out;
1478 : }
1479 130464 : rc = gnutls_hash(hash_hnd,
1480 129270 : backslash.data,
1481 : backslash.length);
1482 129270 : if (rc < 0) {
1483 0 : gnutls_hash_deinit(hash_hnd, NULL);
1484 0 : rc = LDB_ERR_UNWILLING_TO_PERFORM;
1485 0 : goto out;
1486 : }
1487 : }
1488 630576 : rc = gnutls_hash(hash_hnd,
1489 624805 : wdigest[i].user->data,
1490 624805 : wdigest[i].user->length);
1491 624805 : if (rc < 0) {
1492 0 : gnutls_hash_deinit(hash_hnd, NULL);
1493 0 : rc = LDB_ERR_UNWILLING_TO_PERFORM;
1494 0 : goto out;
1495 : }
1496 624805 : rc = gnutls_hash(hash_hnd, delim.data, delim.length);
1497 624805 : if (rc < 0) {
1498 0 : gnutls_hash_deinit(hash_hnd, NULL);
1499 0 : rc = LDB_ERR_UNWILLING_TO_PERFORM;
1500 0 : goto out;
1501 : }
1502 624805 : if (wdigest[i].realm) {
1503 500112 : rc = gnutls_hash(hash_hnd,
1504 495535 : wdigest[i].realm->data,
1505 490958 : wdigest[i].realm->length);
1506 495535 : if (rc < 0) {
1507 0 : gnutls_hash_deinit(hash_hnd, NULL);
1508 0 : rc = LDB_ERR_UNWILLING_TO_PERFORM;
1509 0 : goto out;
1510 : }
1511 : }
1512 624805 : rc = gnutls_hash(hash_hnd, delim.data, delim.length);
1513 624805 : if (rc < 0) {
1514 0 : gnutls_hash_deinit(hash_hnd, NULL);
1515 0 : rc = LDB_ERR_UNWILLING_TO_PERFORM;
1516 0 : goto out;
1517 : }
1518 630576 : rc = gnutls_hash(hash_hnd,
1519 624805 : io->n.cleartext_utf8->data,
1520 624805 : io->n.cleartext_utf8->length);
1521 624805 : if (rc < 0) {
1522 0 : gnutls_hash_deinit(hash_hnd, NULL);
1523 0 : rc = LDB_ERR_UNWILLING_TO_PERFORM;
1524 0 : goto out;
1525 : }
1526 :
1527 624805 : gnutls_hash_deinit(hash_hnd, pdb->hashes[i].hash);
1528 : }
1529 :
1530 21346 : rc = LDB_SUCCESS;
1531 21346 : out:
1532 21346 : return rc;
1533 : }
1534 :
1535 : #define SHA_SALT_PERMITTED_CHARS "abcdefghijklmnopqrstuvwxyz" \
1536 : "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
1537 : "0123456789./"
1538 : #define SHA_SALT_SIZE 16
1539 : #define SHA_256_SCHEME "CryptSHA256"
1540 : #define SHA_512_SCHEME "CryptSHA512"
1541 : #define CRYPT "{CRYPT}"
1542 : #define SHA_ID_LEN 3
1543 : #define SHA_256_ALGORITHM_ID 5
1544 : #define SHA_512_ALGORITHM_ID 6
1545 : #define ROUNDS_PARAMETER "rounds="
1546 :
1547 : /*
1548 : * Extract the crypt (3) algorithm number and number of hash rounds from the
1549 : * supplied scheme string
1550 : */
1551 122 : static bool parse_scheme(const char *scheme, int *algorithm, int *rounds) {
1552 :
1553 122 : const char *rp = NULL; /* Pointer to the 'rounds=' option */
1554 16 : char digits[21]; /* digits extracted from the rounds option */
1555 122 : int i = 0; /* loop index variable */
1556 :
1557 122 : if (strncasecmp(SHA_256_SCHEME, scheme, strlen(SHA_256_SCHEME)) == 0) {
1558 59 : *algorithm = SHA_256_ALGORITHM_ID;
1559 63 : } else if (strncasecmp(SHA_512_SCHEME, scheme, strlen(SHA_256_SCHEME))
1560 : == 0) {
1561 63 : *algorithm = SHA_512_ALGORITHM_ID;
1562 : } else {
1563 0 : return false;
1564 : }
1565 :
1566 122 : rp = strcasestr(scheme, ROUNDS_PARAMETER);
1567 122 : if (rp == NULL) {
1568 : /* No options specified, use crypt default number of rounds */
1569 77 : *rounds = 0;
1570 77 : return true;
1571 : }
1572 45 : rp += strlen(ROUNDS_PARAMETER);
1573 227 : for (i = 0; isdigit(rp[i]) && i < (sizeof(digits) - 1); i++) {
1574 182 : digits[i] = rp[i];
1575 : }
1576 45 : digits[i] = '\0';
1577 45 : *rounds = atoi(digits);
1578 45 : return true;
1579 : }
1580 :
1581 : /*
1582 : * Calculate the password hash specified by scheme, and return it in
1583 : * hash_value
1584 : */
1585 122 : static int setup_primary_userPassword_hash(
1586 : TALLOC_CTX *ctx,
1587 : struct setup_password_fields_io *io,
1588 : const char* scheme,
1589 : struct package_PrimaryUserPasswordValue *hash_value)
1590 : {
1591 122 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1592 122 : const char *salt = NULL; /* Randomly generated salt */
1593 122 : const char *cmd = NULL; /* command passed to crypt */
1594 122 : const char *hash = NULL; /* password hash generated by crypt */
1595 122 : int algorithm = 0; /* crypt hash algorithm number */
1596 122 : int rounds = 0; /* The number of hash rounds */
1597 122 : DATA_BLOB *hash_blob = NULL;
1598 122 : TALLOC_CTX *frame = talloc_stackframe();
1599 : #if defined(HAVE_CRYPT_R) || defined(HAVE_CRYPT_RN)
1600 122 : struct crypt_data crypt_data = {
1601 : .initialized = 0 /* working storage used by crypt */
1602 : };
1603 : #endif
1604 :
1605 : /* Generate a random password salt */
1606 122 : salt = generate_random_str_list(frame,
1607 : SHA_SALT_SIZE,
1608 : SHA_SALT_PERMITTED_CHARS);
1609 122 : if (salt == NULL) {
1610 0 : TALLOC_FREE(frame);
1611 0 : return ldb_oom(ldb);
1612 : }
1613 :
1614 : /* determine the hashing algorithm and number of rounds*/
1615 122 : if (!parse_scheme(scheme, &algorithm, &rounds)) {
1616 0 : ldb_asprintf_errstring(
1617 : ldb,
1618 : "setup_primary_userPassword: Invalid scheme of [%s] "
1619 : "specified for 'password hash userPassword schemes' in "
1620 : "samba.conf",
1621 : scheme);
1622 0 : TALLOC_FREE(frame);
1623 0 : return LDB_ERR_OPERATIONS_ERROR;
1624 : }
1625 122 : hash_value->scheme = talloc_strdup(ctx, CRYPT);
1626 122 : if (hash_value->scheme == NULL) {
1627 0 : TALLOC_FREE(frame);
1628 0 : return ldb_oom(ldb);
1629 : }
1630 122 : hash_value->scheme_len = strlen(CRYPT) + 1;
1631 :
1632 : /* generate the id/salt parameter used by crypt */
1633 122 : if (rounds) {
1634 45 : cmd = talloc_asprintf(frame,
1635 : "$%d$rounds=%d$%s",
1636 : algorithm,
1637 : rounds,
1638 : salt);
1639 45 : if (cmd == NULL) {
1640 0 : TALLOC_FREE(frame);
1641 0 : return ldb_oom(ldb);
1642 : }
1643 : } else {
1644 77 : cmd = talloc_asprintf(frame, "$%d$%s", algorithm, salt);
1645 77 : if (cmd == NULL) {
1646 0 : TALLOC_FREE(frame);
1647 0 : return ldb_oom(ldb);
1648 : }
1649 : }
1650 :
1651 : /*
1652 : * Relies on the assertion that cleartext_utf8->data is a zero
1653 : * terminated UTF-8 string
1654 : */
1655 :
1656 : /*
1657 : * crypt_r() and crypt() may return a null pointer upon error
1658 : * depending on how libcrypt was configured, so we prefer
1659 : * crypt_rn() from libcrypt / libxcrypt which always returns
1660 : * NULL on error.
1661 : *
1662 : * POSIX specifies returning a null pointer and setting
1663 : * errno.
1664 : *
1665 : * RHEL 7 (which does not use libcrypt / libxcrypt) returns a
1666 : * non-NULL pointer from crypt_r() on success but (always?)
1667 : * sets errno during internal processing in the NSS crypto
1668 : * subsystem.
1669 : *
1670 : * By preferring crypt_rn we avoid the 'return non-NULL but
1671 : * set-errno' that we otherwise cannot tell apart from the
1672 : * RHEL 7 behaviour.
1673 : */
1674 122 : errno = 0;
1675 :
1676 : #ifdef HAVE_CRYPT_RN
1677 122 : hash = crypt_rn((char *)io->n.cleartext_utf8->data,
1678 : cmd,
1679 : &crypt_data,
1680 : sizeof(crypt_data));
1681 : #elif HAVE_CRYPT_R
1682 : hash = crypt_r((char *)io->n.cleartext_utf8->data, cmd, &crypt_data);
1683 : #else
1684 : /*
1685 : * No crypt_r falling back to crypt, which is NOT thread safe
1686 : * Thread safety MT-Unsafe race:crypt
1687 : */
1688 : hash = crypt((char *)io->n.cleartext_utf8->data, cmd);
1689 : #endif
1690 : /*
1691 : * On error, crypt() and crypt_r() may return a null pointer,
1692 : * or a pointer to an invalid hash beginning with a '*'.
1693 : */
1694 122 : if (hash == NULL || hash[0] == '*') {
1695 0 : char buf[1024];
1696 0 : const char *reason = NULL;
1697 0 : if (errno == ERANGE) {
1698 0 : reason = "Password exceeds maximum length allowed for crypt() hashing";
1699 : } else {
1700 0 : int err = strerror_r(errno, buf, sizeof(buf));
1701 0 : if (err == 0) {
1702 0 : reason = buf;
1703 : } else {
1704 0 : reason = "Unknown error";
1705 : }
1706 : }
1707 0 : ldb_asprintf_errstring(
1708 : ldb,
1709 : "setup_primary_userPassword: generation of a %s "
1710 : "password hash failed: (%s)",
1711 : scheme,
1712 : reason);
1713 0 : TALLOC_FREE(frame);
1714 0 : return LDB_ERR_OPERATIONS_ERROR;
1715 : }
1716 :
1717 122 : hash_blob = talloc_zero(ctx, DATA_BLOB);
1718 :
1719 122 : if (hash_blob == NULL) {
1720 0 : TALLOC_FREE(frame);
1721 0 : return ldb_oom(ldb);
1722 : }
1723 :
1724 122 : *hash_blob = data_blob_talloc(hash_blob,
1725 : (const uint8_t *)hash,
1726 : strlen(hash));
1727 122 : if (hash_blob->data == NULL) {
1728 0 : TALLOC_FREE(frame);
1729 0 : return ldb_oom(ldb);
1730 : }
1731 122 : hash_value->value = hash_blob;
1732 122 : TALLOC_FREE(frame);
1733 106 : return LDB_SUCCESS;
1734 : }
1735 :
1736 : /*
1737 : * Calculate the desired extra password hashes
1738 : */
1739 44 : static int setup_primary_userPassword(
1740 : struct setup_password_fields_io *io,
1741 : const struct supplementalCredentialsBlob *old_scb,
1742 : struct package_PrimaryUserPasswordBlob *p_userPassword_b)
1743 : {
1744 44 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1745 44 : TALLOC_CTX *frame = talloc_stackframe();
1746 6 : int i;
1747 6 : int ret;
1748 :
1749 : /*
1750 : * Save the current nt_hash, use this to determine if the password
1751 : * has been changed by windows. Which will invalidate the userPassword
1752 : * hash. Note once NTLM-Strong-NOWTF becomes available it should be
1753 : * used in preference to the NT password hash
1754 : */
1755 44 : if (io->g.nt_hash == NULL) {
1756 : /*
1757 : * When the NT hash is not available, we use this field to store
1758 : * the first 16 bytes of the AES256 key instead. This allows
1759 : * 'samba-tool user' to verify that the user's password is in
1760 : * sync with the userPassword package.
1761 : */
1762 14 : uint8_t hash_len = MIN(16, io->g.aes_256.length);
1763 :
1764 14 : ZERO_STRUCT(p_userPassword_b->current_nt_hash);
1765 20 : memcpy(p_userPassword_b->current_nt_hash.hash,
1766 14 : io->g.aes_256.data,
1767 : hash_len);
1768 : } else {
1769 30 : p_userPassword_b->current_nt_hash = *io->g.nt_hash;
1770 : }
1771 :
1772 : /*
1773 : * Determine the number of hashes
1774 : * Note: that currently there is no limit on the number of hashes
1775 : * no checking is done on the number of schemes specified
1776 : * or for uniqueness.
1777 : */
1778 44 : p_userPassword_b->num_hashes = 0;
1779 166 : for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1780 122 : p_userPassword_b->num_hashes++;
1781 : }
1782 :
1783 6 : p_userPassword_b->hashes
1784 44 : = talloc_array(io->ac,
1785 : struct package_PrimaryUserPasswordValue,
1786 : p_userPassword_b->num_hashes);
1787 44 : if (p_userPassword_b->hashes == NULL) {
1788 0 : TALLOC_FREE(frame);
1789 0 : return ldb_oom(ldb);
1790 : }
1791 :
1792 166 : for (i = 0; io->ac->userPassword_schemes[i]; i++) {
1793 138 : ret = setup_primary_userPassword_hash(
1794 106 : p_userPassword_b->hashes,
1795 : io,
1796 106 : io->ac->userPassword_schemes[i],
1797 122 : &p_userPassword_b->hashes[i]);
1798 122 : if (ret != LDB_SUCCESS) {
1799 0 : TALLOC_FREE(frame);
1800 0 : return ret;
1801 : }
1802 : }
1803 44 : TALLOC_FREE(frame);
1804 38 : return LDB_SUCCESS;
1805 : }
1806 :
1807 :
1808 9149 : static int setup_primary_samba_gpg(struct setup_password_fields_io *io,
1809 : struct package_PrimarySambaGPGBlob *pgb)
1810 9149 : {
1811 9149 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
1812 : #ifdef ENABLE_GPGME
1813 127 : gpgme_error_t gret;
1814 9149 : gpgme_ctx_t ctx = NULL;
1815 9149 : size_t num_keys = str_list_length(io->ac->gpg_key_ids);
1816 9149 : gpgme_key_t keys[num_keys+1];
1817 9149 : size_t ki = 0;
1818 9149 : size_t kr = 0;
1819 9149 : gpgme_data_t plain_data = NULL;
1820 9149 : gpgme_data_t crypt_data = NULL;
1821 9149 : size_t crypt_length = 0;
1822 9149 : char *crypt_mem = NULL;
1823 :
1824 9149 : gret = gpgme_new(&ctx);
1825 9149 : if (gret != GPG_ERR_NO_ERROR) {
1826 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
1827 : "%s:%s: gret[%u] %s\n",
1828 : __location__, __func__,
1829 : gret, gpgme_strerror(gret));
1830 0 : return ldb_module_operr(io->ac->module);
1831 : }
1832 :
1833 9149 : gpgme_set_armor(ctx, 1);
1834 :
1835 9276 : gret = gpgme_data_new_from_mem(&plain_data,
1836 9149 : (const char *)io->n.cleartext_utf16->data,
1837 9149 : io->n.cleartext_utf16->length,
1838 : 0 /* no copy */);
1839 9149 : if (gret != GPG_ERR_NO_ERROR) {
1840 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
1841 : "%s:%s: gret[%u] %s\n",
1842 : __location__, __func__,
1843 : gret, gpgme_strerror(gret));
1844 0 : gpgme_release(ctx);
1845 0 : return ldb_module_operr(io->ac->module);
1846 : }
1847 9149 : gret = gpgme_data_new(&crypt_data);
1848 9149 : if (gret != GPG_ERR_NO_ERROR) {
1849 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
1850 : "%s:%s: gret[%u] %s\n",
1851 : __location__, __func__,
1852 : gret, gpgme_strerror(gret));
1853 0 : gpgme_data_release(plain_data);
1854 0 : gpgme_release(ctx);
1855 0 : return ldb_module_operr(io->ac->module);
1856 : }
1857 :
1858 18298 : for (ki = 0; ki < num_keys; ki++) {
1859 9149 : const char *key_id = io->ac->gpg_key_ids[ki];
1860 9149 : size_t len = strlen(key_id);
1861 :
1862 9149 : keys[ki] = NULL;
1863 :
1864 9149 : if (len < 16) {
1865 0 : ldb_debug(ldb, LDB_DEBUG_FATAL,
1866 : "%s:%s: ki[%zu] key_id[%s] strlen < 16, "
1867 : "please specify at least the 64bit key id\n",
1868 : __location__, __func__,
1869 : ki, key_id);
1870 0 : for (kr = 0; keys[kr] != NULL; kr++) {
1871 0 : gpgme_key_release(keys[kr]);
1872 : }
1873 0 : gpgme_data_release(crypt_data);
1874 0 : gpgme_data_release(plain_data);
1875 0 : gpgme_release(ctx);
1876 0 : return ldb_module_operr(io->ac->module);
1877 : }
1878 :
1879 9149 : gret = gpgme_get_key(ctx, key_id, &keys[ki], 0 /* public key */);
1880 9149 : if (gret != GPG_ERR_NO_ERROR) {
1881 0 : keys[ki] = NULL;
1882 0 : if (gpg_err_source(gret) == GPG_ERR_SOURCE_GPGME
1883 0 : && gpg_err_code(gret) == GPG_ERR_EOF) {
1884 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
1885 : "Invalid "
1886 : "'password hash gpg key ids': "
1887 : "Public Key ID [%s] "
1888 : "not found in keyring\n",
1889 : key_id);
1890 :
1891 : } else {
1892 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
1893 : "%s:%s: ki[%zu] key_id[%s] "
1894 : "gret[%u] %s\n",
1895 : __location__, __func__,
1896 : ki, key_id,
1897 : gret, gpgme_strerror(gret));
1898 : }
1899 0 : for (kr = 0; keys[kr] != NULL; kr++) {
1900 0 : gpgme_key_release(keys[kr]);
1901 : }
1902 0 : gpgme_data_release(crypt_data);
1903 0 : gpgme_data_release(plain_data);
1904 0 : gpgme_release(ctx);
1905 0 : return ldb_module_operr(io->ac->module);
1906 : }
1907 : }
1908 9149 : keys[ki] = NULL;
1909 :
1910 9149 : gret = gpgme_op_encrypt(ctx, keys,
1911 : GPGME_ENCRYPT_ALWAYS_TRUST,
1912 : plain_data, crypt_data);
1913 9149 : gpgme_data_release(plain_data);
1914 9149 : plain_data = NULL;
1915 18298 : for (kr = 0; keys[kr] != NULL; kr++) {
1916 9149 : gpgme_key_release(keys[kr]);
1917 9149 : keys[kr] = NULL;
1918 : }
1919 9149 : gpgme_release(ctx);
1920 9149 : ctx = NULL;
1921 9149 : if (gret != GPG_ERR_NO_ERROR) {
1922 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
1923 : "%s:%s: gret[%u] %s\n",
1924 : __location__, __func__,
1925 : gret, gpgme_strerror(gret));
1926 0 : gpgme_data_release(crypt_data);
1927 0 : return ldb_module_operr(io->ac->module);
1928 : }
1929 :
1930 9149 : crypt_mem = gpgme_data_release_and_get_mem(crypt_data, &crypt_length);
1931 9149 : crypt_data = NULL;
1932 9149 : if (crypt_mem == NULL) {
1933 0 : return ldb_module_oom(io->ac->module);
1934 : }
1935 :
1936 9149 : pgb->gpg_blob = data_blob_talloc(io->ac,
1937 : (const uint8_t *)crypt_mem,
1938 : crypt_length);
1939 9149 : gpgme_free(crypt_mem);
1940 9149 : crypt_mem = NULL;
1941 9149 : crypt_length = 0;
1942 9149 : if (pgb->gpg_blob.data == NULL) {
1943 0 : return ldb_module_oom(io->ac->module);
1944 : }
1945 :
1946 9022 : return LDB_SUCCESS;
1947 : #else /* ENABLE_GPGME */
1948 : ldb_debug_set(ldb, LDB_DEBUG_FATAL,
1949 : "You configured 'password hash gpg key ids', "
1950 : "but GPGME support is missing. (%s:%d)",
1951 : __FILE__, __LINE__);
1952 : return LDB_ERR_UNWILLING_TO_PERFORM;
1953 : #endif /* else ENABLE_GPGME */
1954 : }
1955 :
1956 : #define NUM_PACKAGES 6
1957 21905 : static int setup_supplemental_field(struct setup_password_fields_io *io)
1958 : {
1959 205 : struct ldb_context *ldb;
1960 21905 : struct supplementalCredentialsBlob scb = {};
1961 21905 : struct supplementalCredentialsBlob *old_scb = NULL;
1962 : /*
1963 : * Packages +
1964 : * ( Kerberos-Newer-Keys, Kerberos,
1965 : * WDigest, CLEARTEXT, userPassword, SambaGPG)
1966 : */
1967 21905 : uint32_t num_names = 0;
1968 21905 : const char *names[1+NUM_PACKAGES] = {};
1969 21905 : uint32_t num_packages = 0;
1970 21905 : struct supplementalCredentialsPackage packages[1+NUM_PACKAGES] = {};
1971 21905 : struct supplementalCredentialsPackage *pp = packages;
1972 205 : int ret;
1973 205 : enum ndr_err_code ndr_err;
1974 21905 : bool do_newer_keys = false;
1975 21905 : bool do_cleartext = false;
1976 21905 : bool do_samba_gpg = false;
1977 21905 : struct loadparm_context *lp_ctx = NULL;
1978 :
1979 21905 : ldb = ldb_module_get_ctx(io->ac->module);
1980 21905 : lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
1981 : struct loadparm_context);
1982 :
1983 21905 : if (!io->n.cleartext_utf8) {
1984 : /*
1985 : * when we don't have a cleartext password
1986 : * we can't setup a supplementalCredentials value
1987 : */
1988 354 : return LDB_SUCCESS;
1989 : }
1990 :
1991 : /* if there's an old supplementalCredentials blob then use it */
1992 21545 : if (io->o.supplemental) {
1993 2480 : if (io->o.scb.sub.signature == SUPPLEMENTAL_CREDENTIALS_SIGNATURE) {
1994 2478 : old_scb = &io->o.scb;
1995 : } else {
1996 2 : ldb_debug(ldb, LDB_DEBUG_ERROR,
1997 : "setup_supplemental_field: "
1998 : "supplementalCredentialsBlob "
1999 : "signature[0x%04X] expected[0x%04X]",
2000 2 : io->o.scb.sub.signature,
2001 : SUPPLEMENTAL_CREDENTIALS_SIGNATURE);
2002 : }
2003 : }
2004 : /* Per MS-SAMR 3.1.1.8.11.6 we create AES keys if our domain functionality level is 2008 or higher */
2005 :
2006 :
2007 :
2008 : /*
2009 : * The ordering is this
2010 : *
2011 : * Primary:Kerberos-Newer-Keys (optional)
2012 : * Primary:Kerberos
2013 : * Primary:WDigest
2014 : * Primary:CLEARTEXT (optional)
2015 : * Primary:userPassword
2016 : * Primary:SambaGPG (optional)
2017 : *
2018 : * And the 'Packages' package is insert before the last
2019 : * other package.
2020 : *
2021 : * Note: it's important that Primary:SambaGPG is added as
2022 : * the last element. This is the indication that it matches
2023 : * the current password. When a password change happens on
2024 : * a Windows DC, it will keep the old Primary:SambaGPG value,
2025 : * but as the first element.
2026 : */
2027 21545 : do_newer_keys = (dsdb_functional_level(ldb) >= DS_DOMAIN_FUNCTION_2008);
2028 21545 : if (do_newer_keys) {
2029 189 : struct package_PrimaryKerberosBlob pknb;
2030 189 : DATA_BLOB pknb_blob;
2031 189 : char *pknb_hexstr;
2032 : /*
2033 : * setup 'Primary:Kerberos-Newer-Keys' element
2034 : */
2035 16536 : names[num_names++] = "Kerberos-Newer-Keys";
2036 :
2037 16536 : ret = setup_primary_kerberos_newer(io, old_scb, &pknb);
2038 16536 : if (ret != LDB_SUCCESS) {
2039 0 : return ret;
2040 : }
2041 :
2042 16725 : ndr_err = ndr_push_struct_blob(
2043 16536 : &pknb_blob, io->ac,
2044 : &pknb,
2045 : (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
2046 16536 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2047 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2048 0 : ldb_asprintf_errstring(
2049 : ldb,
2050 : "setup_supplemental_field: "
2051 : "failed to push "
2052 : "package_PrimaryKerberosNeverBlob: %s",
2053 : nt_errstr(status));
2054 0 : return LDB_ERR_OPERATIONS_ERROR;
2055 : }
2056 16536 : pknb_hexstr = data_blob_hex_string_upper(io->ac, &pknb_blob);
2057 16536 : if (!pknb_hexstr) {
2058 0 : return ldb_oom(ldb);
2059 : }
2060 16536 : pp->name = "Primary:Kerberos-Newer-Keys";
2061 16536 : pp->reserved = 1;
2062 16536 : pp->data = pknb_hexstr;
2063 16536 : pp++;
2064 16536 : num_packages++;
2065 : }
2066 :
2067 : {
2068 : /*
2069 : * setup 'Primary:Kerberos' element
2070 : */
2071 : /* Primary:Kerberos */
2072 199 : struct package_PrimaryKerberosBlob pkb;
2073 199 : DATA_BLOB pkb_blob;
2074 199 : char *pkb_hexstr;
2075 :
2076 21545 : names[num_names++] = "Kerberos";
2077 :
2078 21545 : ret = setup_primary_kerberos(io, old_scb, &pkb);
2079 21545 : if (ret != LDB_SUCCESS) {
2080 0 : return ret;
2081 : }
2082 :
2083 21744 : ndr_err = ndr_push_struct_blob(
2084 21545 : &pkb_blob, io->ac,
2085 : &pkb,
2086 : (ndr_push_flags_fn_t)ndr_push_package_PrimaryKerberosBlob);
2087 21545 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2088 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2089 0 : ldb_asprintf_errstring(
2090 : ldb,
2091 : "setup_supplemental_field: "
2092 : "failed to push package_PrimaryKerberosBlob: %s",
2093 : nt_errstr(status));
2094 0 : return LDB_ERR_OPERATIONS_ERROR;
2095 : }
2096 21545 : pkb_hexstr = data_blob_hex_string_upper(io->ac, &pkb_blob);
2097 21545 : if (!pkb_hexstr) {
2098 0 : return ldb_oom(ldb);
2099 : }
2100 21545 : pp->name = "Primary:Kerberos";
2101 21545 : pp->reserved = 1;
2102 21545 : pp->data = pkb_hexstr;
2103 21545 : pp++;
2104 21545 : num_packages++;
2105 : }
2106 :
2107 21545 : if (lpcfg_weak_crypto(lp_ctx) == SAMBA_WEAK_CRYPTO_ALLOWED) {
2108 : /*
2109 : * setup 'Primary:WDigest' element
2110 : */
2111 199 : struct package_PrimaryWDigestBlob pdb;
2112 199 : DATA_BLOB pdb_blob;
2113 199 : char *pdb_hexstr;
2114 :
2115 21545 : names[num_names++] = "WDigest";
2116 :
2117 21545 : ret = setup_primary_wdigest(io, old_scb, &pdb);
2118 21545 : if (ret != LDB_SUCCESS) {
2119 0 : return ret;
2120 : }
2121 :
2122 21744 : ndr_err = ndr_push_struct_blob(
2123 21545 : &pdb_blob, io->ac,
2124 : &pdb,
2125 : (ndr_push_flags_fn_t)ndr_push_package_PrimaryWDigestBlob);
2126 21545 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2127 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2128 0 : ldb_asprintf_errstring(
2129 : ldb,
2130 : "setup_supplemental_field: "
2131 : "failed to push package_PrimaryWDigestBlob: %s",
2132 : nt_errstr(status));
2133 0 : return LDB_ERR_OPERATIONS_ERROR;
2134 : }
2135 21545 : pdb_hexstr = data_blob_hex_string_upper(io->ac, &pdb_blob);
2136 21545 : if (!pdb_hexstr) {
2137 0 : return ldb_oom(ldb);
2138 : }
2139 21545 : pp->name = "Primary:WDigest";
2140 21545 : pp->reserved = 1;
2141 21545 : pp->data = pdb_hexstr;
2142 21545 : pp++;
2143 21545 : num_packages++;
2144 : }
2145 :
2146 : /*
2147 : * setup 'Primary:CLEARTEXT' element
2148 : */
2149 21545 : if (io->ac->status->domain_data.store_cleartext &&
2150 14 : (io->u.userAccountControl & UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED)) {
2151 14 : do_cleartext = true;
2152 : }
2153 21346 : if (do_cleartext) {
2154 0 : struct package_PrimaryCLEARTEXTBlob pcb;
2155 0 : DATA_BLOB pcb_blob;
2156 0 : char *pcb_hexstr;
2157 :
2158 14 : names[num_names++] = "CLEARTEXT";
2159 :
2160 14 : pcb.cleartext = *io->n.cleartext_utf16;
2161 :
2162 14 : ndr_err = ndr_push_struct_blob(
2163 14 : &pcb_blob, io->ac,
2164 : &pcb,
2165 : (ndr_push_flags_fn_t)ndr_push_package_PrimaryCLEARTEXTBlob);
2166 14 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2167 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2168 0 : ldb_asprintf_errstring(
2169 : ldb,
2170 : "setup_supplemental_field: "
2171 : "failed to push package_PrimaryCLEARTEXTBlob: %s",
2172 : nt_errstr(status));
2173 0 : return LDB_ERR_OPERATIONS_ERROR;
2174 : }
2175 14 : pcb_hexstr = data_blob_hex_string_upper(io->ac, &pcb_blob);
2176 14 : if (!pcb_hexstr) {
2177 0 : return ldb_oom(ldb);
2178 : }
2179 14 : pp->name = "Primary:CLEARTEXT";
2180 14 : pp->reserved = 1;
2181 14 : pp->data = pcb_hexstr;
2182 14 : pp++;
2183 14 : num_packages++;
2184 : }
2185 :
2186 : /*
2187 : * Don't generate crypt() or similar password for the krbtgt account.
2188 : * It's unnecessary, and the length of the cleartext in UTF-8 form
2189 : * exceeds the maximum (CRYPT_MAX_PASSPHRASE_SIZE) allowed by crypt().
2190 : */
2191 21545 : if (io->ac->userPassword_schemes && !io->u.is_krbtgt) {
2192 : /*
2193 : * setup 'Primary:userPassword' element
2194 : */
2195 6 : struct package_PrimaryUserPasswordBlob
2196 : p_userPassword_b;
2197 6 : DATA_BLOB p_userPassword_b_blob;
2198 6 : char *p_userPassword_b_hexstr;
2199 :
2200 44 : names[num_names++] = "userPassword";
2201 :
2202 44 : ret = setup_primary_userPassword(io,
2203 : old_scb,
2204 : &p_userPassword_b);
2205 44 : if (ret != LDB_SUCCESS) {
2206 0 : return ret;
2207 : }
2208 :
2209 50 : ndr_err = ndr_push_struct_blob(
2210 : &p_userPassword_b_blob,
2211 44 : io->ac,
2212 : &p_userPassword_b,
2213 : (ndr_push_flags_fn_t)
2214 : ndr_push_package_PrimaryUserPasswordBlob);
2215 44 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2216 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2217 0 : ldb_asprintf_errstring(
2218 : ldb,
2219 : "setup_supplemental_field: failed to push "
2220 : "package_PrimaryUserPasswordBlob: %s",
2221 : nt_errstr(status));
2222 0 : return LDB_ERR_OPERATIONS_ERROR;
2223 : }
2224 6 : p_userPassword_b_hexstr
2225 50 : = data_blob_hex_string_upper(
2226 44 : io->ac,
2227 : &p_userPassword_b_blob);
2228 44 : if (!p_userPassword_b_hexstr) {
2229 0 : return ldb_oom(ldb);
2230 : }
2231 44 : pp->name = "Primary:userPassword";
2232 44 : pp->reserved = 1;
2233 44 : pp->data = p_userPassword_b_hexstr;
2234 44 : pp++;
2235 44 : num_packages++;
2236 : }
2237 :
2238 : /*
2239 : * setup 'Primary:SambaGPG' element
2240 : */
2241 21545 : if (io->ac->gpg_key_ids != NULL) {
2242 9149 : do_samba_gpg = true;
2243 : }
2244 21473 : if (do_samba_gpg) {
2245 127 : struct package_PrimarySambaGPGBlob pgb;
2246 127 : DATA_BLOB pgb_blob;
2247 127 : char *pgb_hexstr;
2248 :
2249 9149 : names[num_names++] = "SambaGPG";
2250 :
2251 9149 : ret = setup_primary_samba_gpg(io, &pgb);
2252 9149 : if (ret != LDB_SUCCESS) {
2253 0 : return ret;
2254 : }
2255 :
2256 9149 : ndr_err = ndr_push_struct_blob(&pgb_blob, io->ac, &pgb,
2257 : (ndr_push_flags_fn_t)ndr_push_package_PrimarySambaGPGBlob);
2258 9149 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2259 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2260 0 : ldb_asprintf_errstring(ldb,
2261 : "setup_supplemental_field: failed to "
2262 : "push package_PrimarySambaGPGBlob: %s",
2263 : nt_errstr(status));
2264 0 : return LDB_ERR_OPERATIONS_ERROR;
2265 : }
2266 9149 : pgb_hexstr = data_blob_hex_string_upper(io->ac, &pgb_blob);
2267 9149 : if (!pgb_hexstr) {
2268 0 : return ldb_oom(ldb);
2269 : }
2270 9149 : pp->name = "Primary:SambaGPG";
2271 9149 : pp->reserved = 1;
2272 9149 : pp->data = pgb_hexstr;
2273 9149 : pp++;
2274 9149 : num_packages++;
2275 : }
2276 :
2277 : /*
2278 : * setup 'Packages' element
2279 : */
2280 : {
2281 199 : struct package_PackagesBlob pb;
2282 199 : DATA_BLOB pb_blob;
2283 199 : char *pb_hexstr;
2284 :
2285 21545 : pb.names = names;
2286 21744 : ndr_err = ndr_push_struct_blob(
2287 21545 : &pb_blob, io->ac,
2288 : &pb,
2289 : (ndr_push_flags_fn_t)ndr_push_package_PackagesBlob);
2290 21545 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2291 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2292 0 : ldb_asprintf_errstring(
2293 : ldb,
2294 : "setup_supplemental_field: "
2295 : "failed to push package_PackagesBlob: %s",
2296 : nt_errstr(status));
2297 0 : return LDB_ERR_OPERATIONS_ERROR;
2298 : }
2299 21545 : pb_hexstr = data_blob_hex_string_upper(io->ac, &pb_blob);
2300 21545 : if (!pb_hexstr) {
2301 0 : return ldb_oom(ldb);
2302 : }
2303 21545 : pp->name = "Packages";
2304 21545 : pp->reserved = 2;
2305 21545 : pp->data = pb_hexstr;
2306 21545 : num_packages++;
2307 : /*
2308 : * We don't increment pp so it's pointing to the last package
2309 : */
2310 : }
2311 :
2312 : /*
2313 : * setup 'supplementalCredentials' value
2314 : */
2315 : {
2316 : /*
2317 : * The 'Packages' element needs to be the second last element
2318 : * in supplementalCredentials
2319 : */
2320 199 : struct supplementalCredentialsPackage temp;
2321 199 : struct supplementalCredentialsPackage *prev;
2322 :
2323 21545 : prev = pp-1;
2324 21545 : temp = *prev;
2325 21545 : *prev = *pp;
2326 21545 : *pp = temp;
2327 :
2328 21545 : scb.sub.signature = SUPPLEMENTAL_CREDENTIALS_SIGNATURE;
2329 21545 : scb.sub.num_packages = num_packages;
2330 21545 : scb.sub.packages = packages;
2331 :
2332 21744 : ndr_err = ndr_push_struct_blob(
2333 21545 : &io->g.supplemental, io->ac,
2334 : &scb,
2335 : (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2336 21545 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2337 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2338 0 : ldb_asprintf_errstring(
2339 : ldb,
2340 : "setup_supplemental_field: "
2341 : "failed to push supplementalCredentialsBlob: %s",
2342 : nt_errstr(status));
2343 0 : return LDB_ERR_OPERATIONS_ERROR;
2344 : }
2345 : }
2346 :
2347 21346 : return LDB_SUCCESS;
2348 : }
2349 :
2350 48404 : static int setup_last_set_field(struct setup_password_fields_io *io)
2351 : {
2352 48404 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2353 48404 : const struct ldb_message *msg = NULL;
2354 48404 : const struct ldb_val *old_val = NULL;
2355 48404 : const struct ldb_val *new_val = NULL;
2356 360 : int ret;
2357 360 : bool ok;
2358 :
2359 48404 : switch (io->ac->req->operation) {
2360 30247 : case LDB_ADD:
2361 30247 : msg = io->ac->req->op.add.message;
2362 30247 : break;
2363 18157 : case LDB_MODIFY:
2364 18157 : msg = io->ac->req->op.mod.message;
2365 18157 : break;
2366 0 : default:
2367 0 : return LDB_ERR_OPERATIONS_ERROR;
2368 360 : break;
2369 : }
2370 :
2371 48404 : if (io->ac->pwd_last_set_bypass) {
2372 5 : struct ldb_message_element *el = NULL;
2373 0 : size_t i;
2374 5 : size_t count = 0;
2375 : /*
2376 : * This is a message from pdb_samba_dsdb_replace_by_sam()
2377 : *
2378 : * We want to ensure there is only one pwdLastSet element, and
2379 : * it isn't deleting.
2380 : */
2381 5 : if (msg == NULL) {
2382 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
2383 : }
2384 :
2385 16 : for (i = 0; i < msg->num_elements; i++) {
2386 11 : if (ldb_attr_cmp(msg->elements[i].name,
2387 : "pwdLastSet") == 0) {
2388 5 : count++;
2389 5 : el = &msg->elements[i];
2390 : }
2391 : }
2392 5 : if (count != 1) {
2393 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
2394 : }
2395 :
2396 5 : if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
2397 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
2398 : }
2399 :
2400 5 : io->g.last_set = samdb_result_nttime(msg, "pwdLastSet", 0);
2401 5 : return LDB_SUCCESS;
2402 : }
2403 :
2404 48399 : ret = msg_find_old_and_new_pwd_val(msg, "pwdLastSet",
2405 48039 : io->ac->req->operation,
2406 : &new_val, &old_val);
2407 48399 : if (ret != LDB_SUCCESS) {
2408 0 : return ret;
2409 : }
2410 :
2411 48399 : if (old_val != NULL && new_val == NULL) {
2412 0 : ldb_set_errstring(ldb,
2413 : "'pwdLastSet' deletion is not allowed!");
2414 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
2415 : }
2416 :
2417 48399 : io->g.last_set = UINT64_MAX;
2418 48399 : if (new_val != NULL) {
2419 30451 : struct ldb_message *tmp_msg = NULL;
2420 :
2421 30451 : tmp_msg = ldb_msg_new(io->ac);
2422 30451 : if (tmp_msg == NULL) {
2423 0 : return ldb_module_oom(io->ac->module);
2424 : }
2425 :
2426 30451 : if (old_val != NULL) {
2427 18 : NTTIME old_last_set = 0;
2428 :
2429 18 : ret = ldb_msg_add_value(tmp_msg, "oldval",
2430 : old_val, NULL);
2431 18 : if (ret != LDB_SUCCESS) {
2432 0 : return ret;
2433 : }
2434 :
2435 18 : old_last_set = samdb_result_nttime(tmp_msg,
2436 : "oldval",
2437 : 1);
2438 18 : if (io->u.pwdLastSet != old_last_set) {
2439 6 : return dsdb_module_werror(io->ac->module,
2440 : LDB_ERR_NO_SUCH_ATTRIBUTE,
2441 : WERR_DS_CANT_REM_MISSING_ATT_VAL,
2442 : "setup_last_set_field: old pwdLastSet "
2443 : "value not found!");
2444 : }
2445 : }
2446 :
2447 30445 : ret = ldb_msg_add_value(tmp_msg, "newval",
2448 : new_val, NULL);
2449 30445 : if (ret != LDB_SUCCESS) {
2450 0 : return ret;
2451 : }
2452 :
2453 30445 : io->g.last_set = samdb_result_nttime(tmp_msg,
2454 : "newval",
2455 : 1);
2456 17948 : } else if (ldb_msg_find_element(msg, "pwdLastSet")) {
2457 0 : ldb_set_errstring(ldb,
2458 : "'pwdLastSet' deletion is not allowed!");
2459 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
2460 17948 : } else if (io->ac->smartcard_reset) {
2461 : /*
2462 : * adding UF_SMARTCARD_REQUIRED doesn't update
2463 : * pwdLastSet implicitly.
2464 : */
2465 11 : io->ac->update_lastset = false;
2466 : }
2467 :
2468 : /* only 0 or -1 (0xFFFFFFFFFFFFFFFF) are allowed */
2469 48393 : switch (io->g.last_set) {
2470 30374 : case 0:
2471 30374 : if (!io->ac->pwd_last_set_default) {
2472 189 : break;
2473 : }
2474 30183 : if (!io->ac->update_password) {
2475 26068 : break;
2476 : }
2477 205 : FALL_THROUGH;
2478 : case UINT64_MAX:
2479 21972 : if (!io->ac->update_password &&
2480 73 : io->u.pwdLastSet != 0 &&
2481 52 : io->u.pwdLastSet != UINT64_MAX)
2482 : {
2483 : /*
2484 : * Just setting pwdLastSet to -1, while not changing
2485 : * any password field has no effect if pwdLastSet
2486 : * is already non-zero.
2487 : */
2488 52 : io->ac->update_lastset = false;
2489 52 : break;
2490 : }
2491 : /* -1 means set it as now */
2492 21920 : ok = dsdb_gmsa_current_time(ldb, &io->g.last_set);
2493 21920 : if (!ok) {
2494 9 : return LDB_ERR_OPERATIONS_ERROR;
2495 : }
2496 21715 : break;
2497 9 : default:
2498 9 : return dsdb_module_werror(io->ac->module,
2499 : LDB_ERR_OTHER,
2500 : WERR_INVALID_PARAMETER,
2501 : "setup_last_set_field: "
2502 : "pwdLastSet must be 0 or -1 only!");
2503 : }
2504 :
2505 48384 : if (io->ac->req->operation == LDB_ADD) {
2506 : /*
2507 : * We always need to store the value on add
2508 : * operations.
2509 : */
2510 30020 : return LDB_SUCCESS;
2511 : }
2512 :
2513 18143 : if (io->g.last_set == io->u.pwdLastSet) {
2514 : /*
2515 : * Just setting pwdLastSet to 0, is no-op if it's already 0.
2516 : */
2517 84 : io->ac->update_lastset = false;
2518 : }
2519 :
2520 18004 : return LDB_SUCCESS;
2521 : }
2522 :
2523 43814 : static int setup_given_passwords(struct setup_password_fields_io *io,
2524 : struct setup_password_fields_given *g)
2525 : {
2526 43814 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2527 :
2528 43814 : if (g->cleartext_utf8) {
2529 0 : struct ldb_val *cleartext_utf16_blob;
2530 :
2531 2419 : cleartext_utf16_blob = talloc(io->ac, struct ldb_val);
2532 2419 : if (!cleartext_utf16_blob) {
2533 0 : return ldb_oom(ldb);
2534 : }
2535 2419 : if (!convert_string_talloc(io->ac,
2536 : CH_UTF8, CH_UTF16,
2537 2419 : g->cleartext_utf8->data,
2538 2419 : g->cleartext_utf8->length,
2539 2419 : &cleartext_utf16_blob->data,
2540 : &cleartext_utf16_blob->length)) {
2541 0 : if (g->cleartext_utf8->length != 0) {
2542 0 : talloc_free(cleartext_utf16_blob);
2543 0 : ldb_asprintf_errstring(ldb,
2544 : "setup_password_fields: "
2545 : "failed to generate UTF16 password from cleartext UTF8 one for user '%s'!",
2546 : io->u.sAMAccountName);
2547 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
2548 : } else {
2549 : /* passwords with length "0" are valid! */
2550 0 : cleartext_utf16_blob->data = NULL;
2551 0 : cleartext_utf16_blob->length = 0;
2552 : }
2553 : }
2554 2419 : g->cleartext_utf16 = cleartext_utf16_blob;
2555 41395 : } else if (g->cleartext_utf16) {
2556 199 : struct ldb_val *cleartext_utf8_blob;
2557 :
2558 20256 : cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
2559 20256 : if (!cleartext_utf8_blob) {
2560 0 : return ldb_oom(ldb);
2561 : }
2562 20256 : if (!convert_string_talloc(io->ac,
2563 : CH_UTF16MUNGED, CH_UTF8,
2564 20256 : g->cleartext_utf16->data,
2565 20256 : g->cleartext_utf16->length,
2566 20256 : &cleartext_utf8_blob->data,
2567 : &cleartext_utf8_blob->length)) {
2568 0 : if (g->cleartext_utf16->length != 0) {
2569 : /* We must bail out here, the input wasn't even
2570 : * a multiple of 2 bytes */
2571 0 : talloc_free(cleartext_utf8_blob);
2572 0 : ldb_asprintf_errstring(ldb,
2573 : "setup_password_fields: "
2574 : "failed to generate UTF8 password from cleartext UTF 16 one for user '%s' - the latter had odd length (length must be a multiple of 2)!",
2575 : io->u.sAMAccountName);
2576 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
2577 : } else {
2578 : /* passwords with length "0" are valid! */
2579 0 : cleartext_utf8_blob->data = NULL;
2580 0 : cleartext_utf8_blob->length = 0;
2581 : }
2582 : }
2583 20256 : g->cleartext_utf8 = cleartext_utf8_blob;
2584 : }
2585 :
2586 43814 : if (g->cleartext_utf16) {
2587 199 : struct samr_Password *nt_hash;
2588 :
2589 22675 : nt_hash = talloc(io->ac, struct samr_Password);
2590 22675 : if (!nt_hash) {
2591 0 : return ldb_oom(ldb);
2592 : }
2593 22675 : g->nt_hash = nt_hash;
2594 :
2595 : /* compute the new nt hash */
2596 22675 : mdfour(nt_hash->hash,
2597 22675 : g->cleartext_utf16->data,
2598 22675 : g->cleartext_utf16->length);
2599 : }
2600 :
2601 : /*
2602 : * We need to build one more hash, so we can compare with what might
2603 : * have been stored in the old password (for the LDAP password change)
2604 : *
2605 : * We don't have any old salts, so we won't catch password reuse if said
2606 : * password was used prior to an account rename and another password
2607 : * change.
2608 : *
2609 : * We don't have to store the 'opaque' (string2key iterations)
2610 : * as Heimdal doesn't allow that to be changed.
2611 : */
2612 43814 : if (g->cleartext_utf8 != NULL) {
2613 22675 : int ret = setup_kerberos_key_hash(io, g);
2614 22675 : if (ret != LDB_SUCCESS) {
2615 0 : return ret;
2616 : }
2617 : }
2618 :
2619 43404 : return LDB_SUCCESS;
2620 : }
2621 :
2622 48404 : static int setup_password_fields(struct setup_password_fields_io *io)
2623 : {
2624 48404 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2625 360 : int ret;
2626 :
2627 48404 : ret = setup_last_set_field(io);
2628 48404 : if (ret != LDB_SUCCESS) {
2629 15 : return ret;
2630 : }
2631 :
2632 48389 : if (!io->ac->update_password) {
2633 26327 : return LDB_SUCCESS;
2634 : }
2635 :
2636 21907 : if (io->u.is_krbtgt) {
2637 291 : size_t min = 196;
2638 291 : size_t max = 255;
2639 291 : size_t diff = max - min;
2640 291 : size_t len = max;
2641 291 : struct ldb_val *krbtgt_utf16 = NULL;
2642 :
2643 291 : if (!io->ac->pwd_reset) {
2644 0 : return dsdb_module_werror(io->ac->module,
2645 : LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS,
2646 : WERR_DS_ATT_ALREADY_EXISTS,
2647 : "Password change on krbtgt not permitted!");
2648 : }
2649 :
2650 291 : if (io->n.cleartext_utf16 == NULL) {
2651 0 : return dsdb_module_werror(io->ac->module,
2652 : LDB_ERR_UNWILLING_TO_PERFORM,
2653 : WERR_DS_INVALID_ATTRIBUTE_SYNTAX,
2654 : "Password reset on krbtgt requires UTF16!");
2655 : }
2656 :
2657 : /*
2658 : * Instead of taking the callers value,
2659 : * we just generate a new random value here.
2660 : *
2661 : * Include null termination in the array.
2662 : */
2663 291 : if (diff > 0) {
2664 22 : size_t tmp;
2665 :
2666 291 : generate_random_buffer((uint8_t *)&tmp, sizeof(tmp));
2667 :
2668 291 : tmp %= diff;
2669 :
2670 291 : len = min + tmp;
2671 : }
2672 :
2673 291 : krbtgt_utf16 = talloc_zero(io->ac, struct ldb_val);
2674 291 : if (krbtgt_utf16 == NULL) {
2675 0 : return ldb_oom(ldb);
2676 : }
2677 :
2678 291 : *krbtgt_utf16 = data_blob_talloc_zero(krbtgt_utf16,
2679 291 : (len+1)*2);
2680 291 : if (krbtgt_utf16->data == NULL) {
2681 0 : return ldb_oom(ldb);
2682 : }
2683 291 : krbtgt_utf16->length = len * 2;
2684 291 : generate_secret_buffer(krbtgt_utf16->data,
2685 : krbtgt_utf16->length);
2686 291 : io->n.cleartext_utf16 = krbtgt_utf16;
2687 : }
2688 :
2689 : /* transform the old password (for password changes) */
2690 21907 : ret = setup_given_passwords(io, &io->og);
2691 21907 : if (ret != LDB_SUCCESS) {
2692 0 : return ret;
2693 : }
2694 :
2695 : /* transform the new password */
2696 21907 : ret = setup_given_passwords(io, &io->n);
2697 21907 : if (ret != LDB_SUCCESS) {
2698 0 : return ret;
2699 : }
2700 :
2701 21907 : if (io->n.cleartext_utf8) {
2702 21547 : ret = setup_kerberos_keys(io);
2703 21547 : if (ret != LDB_SUCCESS) {
2704 2 : return ret;
2705 : }
2706 : }
2707 :
2708 : /*
2709 : * This relies on setup_kerberos_keys to make a NT-hash-like
2710 : * value for password history purposes
2711 : */
2712 :
2713 21905 : ret = setup_nt_fields(io);
2714 21905 : if (ret != LDB_SUCCESS) {
2715 0 : return ret;
2716 : }
2717 :
2718 21905 : ret = setup_supplemental_field(io);
2719 21905 : if (ret != LDB_SUCCESS) {
2720 0 : return ret;
2721 : }
2722 :
2723 21700 : return LDB_SUCCESS;
2724 : }
2725 :
2726 47424 : static int setup_smartcard_reset(struct setup_password_fields_io *io)
2727 : {
2728 47424 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2729 47424 : struct supplementalCredentialsBlob scb = { .__ndr_size = 0 };
2730 360 : enum ndr_err_code ndr_err;
2731 :
2732 47424 : if (!io->ac->smartcard_reset) {
2733 47041 : return LDB_SUCCESS;
2734 : }
2735 :
2736 23 : io->g.nt_hash = talloc(io->ac, struct samr_Password);
2737 23 : if (io->g.nt_hash == NULL) {
2738 0 : return ldb_module_oom(io->ac->module);
2739 : }
2740 23 : generate_secret_buffer(io->g.nt_hash->hash,
2741 : sizeof(io->g.nt_hash->hash));
2742 23 : io->g.nt_history_len = 0;
2743 :
2744 : /*
2745 : * We take the "old" value and store it
2746 : * with num_packages = 0.
2747 : *
2748 : * On "add" we have scb.sub.signature == 0, which
2749 : * results in:
2750 : *
2751 : * [0000] 00 00 00 00 00 00 00 00 00 00 00 00 00
2752 : *
2753 : * On modify it's likely to be scb.sub.signature ==
2754 : * SUPPLEMENTAL_CREDENTIALS_SIGNATURE (0x0050), which results in
2755 : * something like:
2756 : *
2757 : * [0000] 00 00 00 00 62 00 00 00 00 00 00 00 20 00 20 00
2758 : * [0010] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2759 : * [0020] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2760 : * [0030] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2761 : * [0040] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2762 : * [0050] 20 00 20 00 20 00 20 00 20 00 20 00 20 00 20 00
2763 : * [0060] 20 00 20 00 20 00 20 00 20 00 20 00 50 00 00
2764 : *
2765 : * See https://bugzilla.samba.org/show_bug.cgi?id=11441
2766 : * and ndr_{push,pull}_supplementalCredentialsSubBlob().
2767 : */
2768 23 : scb = io->o.scb;
2769 23 : scb.sub.num_packages = 0;
2770 :
2771 : /*
2772 : * setup 'supplementalCredentials' value without packages
2773 : */
2774 23 : ndr_err = ndr_push_struct_blob(&io->g.supplemental, io->ac,
2775 : &scb,
2776 : (ndr_push_flags_fn_t)ndr_push_supplementalCredentialsBlob);
2777 23 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
2778 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
2779 0 : ldb_asprintf_errstring(ldb,
2780 : "setup_smartcard_reset: "
2781 : "failed to push supplementalCredentialsBlob: %s",
2782 : nt_errstr(status));
2783 0 : return LDB_ERR_OPERATIONS_ERROR;
2784 : }
2785 :
2786 23 : io->ac->update_password = true;
2787 23 : return LDB_SUCCESS;
2788 : }
2789 :
2790 435 : static int make_error_and_update_badPwdCount(struct setup_password_fields_io *io, WERROR *werror)
2791 : {
2792 435 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2793 435 : struct ldb_message *mod_msg = NULL;
2794 435 : struct ldb_message *pso_msg = NULL;
2795 435 : struct ldb_message *current = NULL;
2796 435 : NTSTATUS status = NT_STATUS_OK;
2797 0 : int ret; /* The errors we will actually return */
2798 0 : int dbg_ret; /* The errors we can only complain about in logs */
2799 :
2800 : /*
2801 : * OK, horrible semantics ahead.
2802 : *
2803 : * - We need to abort any existing transaction
2804 : * - create a transaction around the badPwdCount update
2805 : * - re-open the transaction so the upper layer
2806 : * doesn't know what happened.
2807 : *
2808 : * This is needed because returning an error to the upper
2809 : * layer will cancel the transaction and undo the badPwdCount
2810 : * update.
2811 : */
2812 :
2813 : /*
2814 : * Checking errors here is a bit pointless.
2815 : * What can we do if we can't end the transaction?
2816 : */
2817 435 : dbg_ret = ldb_next_del_trans(io->ac->module);
2818 435 : if (dbg_ret != LDB_SUCCESS) {
2819 0 : ldb_debug(ldb, LDB_DEBUG_FATAL,
2820 : "Failed to abort transaction prior to update of badPwdCount of %s: %s",
2821 0 : ldb_dn_get_linearized(io->ac->search_res->message->dn),
2822 : ldb_errstring(ldb));
2823 : /*
2824 : * just return the original error
2825 : */
2826 0 : goto done;
2827 : }
2828 :
2829 : /* Likewise, what should we do if we can't open a new transaction? */
2830 435 : dbg_ret = ldb_next_start_trans(io->ac->module);
2831 435 : if (dbg_ret != LDB_SUCCESS) {
2832 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
2833 : "Failed to open transaction to update badPwdCount of %s: %s",
2834 0 : ldb_dn_get_linearized(io->ac->search_res->message->dn),
2835 : ldb_errstring(ldb));
2836 : /*
2837 : * just return the original error
2838 : */
2839 0 : goto done;
2840 : }
2841 :
2842 : /*
2843 : * Re-read the account details, using the GUID in case the DN
2844 : * is being changed.
2845 : */
2846 435 : status = authsam_reread_user_logon_data(
2847 435 : ldb, io->ac,
2848 435 : io->ac->search_res->message,
2849 : ¤t);
2850 435 : if (!NT_STATUS_IS_OK(status)) {
2851 : /* The re-read can return account locked out, as well
2852 : * as an internal error
2853 : */
2854 0 : goto end_transaction;
2855 : }
2856 :
2857 : /* PSO search result is optional (NULL if no PSO applies) */
2858 435 : if (io->ac->pso_res != NULL) {
2859 15 : pso_msg = io->ac->pso_res->message;
2860 : }
2861 :
2862 435 : status = dsdb_update_bad_pwd_count(io->ac, ldb,
2863 : current,
2864 435 : io->ac->dom_res->message,
2865 : pso_msg,
2866 : &mod_msg);
2867 435 : if (!NT_STATUS_IS_OK(status)) {
2868 0 : goto end_transaction;
2869 : }
2870 :
2871 435 : if (mod_msg == NULL) {
2872 263 : goto end_transaction;
2873 : }
2874 :
2875 172 : dbg_ret = dsdb_module_modify(io->ac->module, mod_msg,
2876 : DSDB_FLAG_NEXT_MODULE,
2877 172 : io->ac->req);
2878 172 : if (dbg_ret != LDB_SUCCESS) {
2879 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
2880 : "Failed to update badPwdCount of %s: %s",
2881 0 : ldb_dn_get_linearized(io->ac->search_res->message->dn),
2882 : ldb_errstring(ldb));
2883 : /*
2884 : * We can only ignore this...
2885 : */
2886 : }
2887 :
2888 172 : end_transaction:
2889 435 : dbg_ret = ldb_next_end_trans(io->ac->module);
2890 435 : if (dbg_ret != LDB_SUCCESS) {
2891 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
2892 : "Failed to close transaction to update badPwdCount of %s: %s",
2893 0 : ldb_dn_get_linearized(io->ac->search_res->message->dn),
2894 : ldb_errstring(ldb));
2895 : /*
2896 : * We can only ignore this...
2897 : */
2898 : }
2899 :
2900 435 : dbg_ret = ldb_next_start_trans(io->ac->module);
2901 435 : if (dbg_ret != LDB_SUCCESS) {
2902 0 : ldb_debug(ldb, LDB_DEBUG_ERROR,
2903 : "Failed to open transaction after update of badPwdCount of %s: %s",
2904 0 : ldb_dn_get_linearized(io->ac->search_res->message->dn),
2905 : ldb_errstring(ldb));
2906 : /*
2907 : * We can only ignore this...
2908 : */
2909 : }
2910 :
2911 435 : done:
2912 435 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
2913 435 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
2914 0 : *werror = WERR_ACCOUNT_LOCKED_OUT;
2915 : } else {
2916 435 : *werror = WERR_INVALID_PASSWORD;
2917 : }
2918 435 : ldb_asprintf_errstring(ldb,
2919 : "%08X: %s - check_password_restrictions: "
2920 : "The old password specified doesn't match!",
2921 : W_ERROR_V(*werror),
2922 : ldb_strerror(ret));
2923 435 : return ret;
2924 : }
2925 :
2926 48387 : static int check_password_restrictions(struct setup_password_fields_io *io, WERROR *werror)
2927 : {
2928 48387 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
2929 360 : int ret;
2930 360 : uint32_t i;
2931 360 : struct loadparm_context *lp_ctx =
2932 48387 : talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
2933 : struct loadparm_context);
2934 360 : struct dsdb_encrypted_connection_state *opaque_connection_state =
2935 48387 : ldb_get_opaque(ldb,DSDB_OPAQUE_ENCRYPTED_CONNECTION_STATE_NAME);
2936 :
2937 48387 : *werror = WERR_INVALID_PARAMETER;
2938 :
2939 48387 : if (!io->ac->update_password) {
2940 26327 : return LDB_SUCCESS;
2941 : }
2942 :
2943 : /*
2944 : * Prevent update password on an insecure connection.
2945 : * The opaque is added in the ldap backend init.
2946 : */
2947 21905 : if (opaque_connection_state != NULL &&
2948 18230 : !opaque_connection_state->using_encrypted_connection) {
2949 4 : ret = LDB_ERR_UNWILLING_TO_PERFORM;
2950 4 : *werror = WERR_GEN_FAILURE;
2951 4 : ldb_asprintf_errstring(ldb,
2952 : "%08X: SvcErr: DSID-031A126C, "
2953 : "problem 5003 (WILL_NOT_PERFORM), "
2954 : "data 0\n"
2955 : "Password modification over LDAP "
2956 : "must be over an encrypted connection",
2957 : W_ERROR_V(*werror));
2958 4 : return ret;
2959 : }
2960 :
2961 : /*
2962 : * First check the old password is correct, for password
2963 : * changes when this hasn't already been checked by a
2964 : * trustworthy layer above
2965 : */
2966 21901 : if (!io->ac->pwd_reset && !(io->ac->change
2967 883 : && io->ac->change->old_password_checked == DSDB_PASSWORD_CHECKED_AND_CORRECT)) {
2968 1128 : bool hash_checked = false;
2969 : /*
2970 : * we need the old nt hash given by the client (this
2971 : * is for the plaintext over LDAP password change,
2972 : * Kpasswd and SAMR supply the control)
2973 : */
2974 1128 : if (io->og.nt_hash == NULL && io->og.aes_256.length == 0) {
2975 0 : ldb_asprintf_errstring(ldb,
2976 : "check_password_restrictions: "
2977 : "You need to provide the old password in order "
2978 : "to change it!");
2979 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
2980 : }
2981 :
2982 : /*
2983 : * First compare the ENCTYPE_AES256_CTS_HMAC_SHA1_96 password and see if we have a match
2984 : */
2985 :
2986 1128 : if (io->og.aes_256.length > 0 && io->o.aes_256.length) {
2987 838 : hash_checked = data_blob_equal_const_time(&io->og.aes_256, &io->o.aes_256);
2988 : }
2989 :
2990 : /* The password modify through the NT hash is encouraged and
2991 : has no problems at all */
2992 1128 : if (!hash_checked && io->og.nt_hash && io->o.nt_hash) {
2993 237 : hash_checked = mem_equal_const_time(io->og.nt_hash->hash, io->o.nt_hash->hash, 16);
2994 : }
2995 :
2996 1128 : if (!hash_checked) {
2997 435 : return make_error_and_update_badPwdCount(io, werror);
2998 : }
2999 : }
3000 :
3001 21466 : if (io->u.restrictions == 0) {
3002 : /* FIXME: Is this right? */
3003 3605 : return LDB_SUCCESS;
3004 : }
3005 :
3006 : /* Password minimum age: yes, this is a minus. The ages are in negative 100nsec units! */
3007 17712 : if ((io->u.pwdLastSet - io->ac->status->domain_data.minPwdAge > io->g.last_set) &&
3008 526 : !io->ac->pwd_reset)
3009 : {
3010 159 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
3011 159 : *werror = WERR_PASSWORD_RESTRICTION;
3012 159 : ldb_asprintf_errstring(ldb,
3013 : "%08X: %s - check_password_restrictions: "
3014 : "password is too young to change!",
3015 : W_ERROR_V(*werror),
3016 : ldb_strerror(ret));
3017 159 : return ret;
3018 : }
3019 :
3020 : /*
3021 : * Fundamental password checks done by the call
3022 : * "samdb_check_password".
3023 : * It is also in use by "dcesrv_samr_ValidatePassword".
3024 : */
3025 17553 : if (io->n.cleartext_utf8 != NULL) {
3026 56 : enum samr_ValidationStatus vstat;
3027 17455 : vstat = samdb_check_password(io->ac, lp_ctx,
3028 : io->u.sAMAccountName,
3029 : io->u.user_principal_name,
3030 : io->u.displayName,
3031 17399 : io->n.cleartext_utf8,
3032 17399 : io->ac->status->domain_data.pwdProperties,
3033 17399 : io->ac->status->domain_data.minPwdLength);
3034 17455 : switch (vstat) {
3035 17156 : case SAMR_VALIDATION_STATUS_SUCCESS:
3036 : /* perfect -> proceed! */
3037 17156 : break;
3038 :
3039 191 : case SAMR_VALIDATION_STATUS_PWD_TOO_SHORT:
3040 191 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
3041 191 : *werror = WERR_PASSWORD_RESTRICTION;
3042 191 : ldb_asprintf_errstring(ldb,
3043 : "%08X: %s - check_password_restrictions: "
3044 : "the password is too short. It should be equal to or longer than %u characters!",
3045 : W_ERROR_V(*werror),
3046 : ldb_strerror(ret),
3047 191 : io->ac->status->domain_data.minPwdLength);
3048 191 : io->ac->status->reject_reason = SAM_PWD_CHANGE_PASSWORD_TOO_SHORT;
3049 243 : return ret;
3050 :
3051 52 : case SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH:
3052 52 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
3053 52 : *werror = WERR_PASSWORD_RESTRICTION;
3054 52 : ldb_asprintf_errstring(ldb,
3055 : "%08X: %s - check_password_restrictions: "
3056 : "the password does not meet the complexity criteria!",
3057 : W_ERROR_V(*werror),
3058 : ldb_strerror(ret));
3059 52 : io->ac->status->reject_reason = SAM_PWD_CHANGE_NOT_COMPLEX;
3060 52 : return ret;
3061 :
3062 0 : default:
3063 0 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
3064 0 : *werror = WERR_PASSWORD_RESTRICTION;
3065 0 : ldb_asprintf_errstring(ldb,
3066 : "%08X: %s - check_password_restrictions: "
3067 : "the password doesn't fit due to a miscellaneous restriction!",
3068 : W_ERROR_V(*werror),
3069 : ldb_strerror(ret));
3070 0 : return ret;
3071 : }
3072 : }
3073 :
3074 17310 : if (io->ac->pwd_reset) {
3075 16694 : *werror = WERR_OK;
3076 16694 : return LDB_SUCCESS;
3077 : }
3078 :
3079 : /*
3080 : * This check works by using the current Kerberos password to
3081 : * make up a password history. We already did the salted hash
3082 : * creation to pass the password change check.
3083 : *
3084 : * We check the pwdHistoryLength to ensure we honour the
3085 : * policy on if the history should be checked
3086 : */
3087 616 : if (io->ac->status->domain_data.pwdHistoryLength > 0
3088 599 : && io->g.aes_256.length && io->o.aes_256.length)
3089 : {
3090 543 : bool equal = data_blob_equal_const_time(&io->g.aes_256,
3091 543 : &io->o.aes_256);
3092 543 : if (equal) {
3093 47 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
3094 47 : *werror = WERR_PASSWORD_RESTRICTION;
3095 47 : ldb_asprintf_errstring(ldb,
3096 : "%08X: %s - check_password_restrictions: "
3097 : "the password was already used (previous password)!",
3098 : W_ERROR_V(*werror),
3099 : ldb_strerror(ret));
3100 47 : io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
3101 47 : return ret;
3102 : }
3103 : }
3104 :
3105 569 : if (io->n.nt_hash) {
3106 : /*
3107 : * checks the NT hash password history, against the
3108 : * generated NT hash
3109 : */
3110 1597 : for (i = 0; i < io->o.nt_history_len; i++) {
3111 1095 : bool pw_cmp = mem_equal_const_time(io->n.nt_hash, io->o.nt_history[i].hash, 16);
3112 1095 : if (pw_cmp) {
3113 67 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
3114 67 : *werror = WERR_PASSWORD_RESTRICTION;
3115 67 : ldb_asprintf_errstring(ldb,
3116 : "%08X: %s - check_password_restrictions: "
3117 : "the password was already used (in history)!",
3118 : W_ERROR_V(*werror),
3119 : ldb_strerror(ret));
3120 67 : io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
3121 67 : return ret;
3122 : }
3123 : }
3124 : }
3125 :
3126 : /*
3127 : * This check works by using the old Kerberos passwords
3128 : * (old and older) to make up a password history.
3129 : *
3130 : * We check the pwdHistoryLength to ensure we honour the
3131 : * policy on if the history should be checked
3132 : */
3133 502 : for (i = 1;
3134 854 : i <= io->o.kvno && i < MIN(3, io->ac->status->domain_data.pwdHistoryLength);
3135 352 : i++)
3136 : {
3137 0 : krb5_error_code krb5_ret;
3138 626 : const uint32_t request_kvno = io->o.kvno - i;
3139 0 : DATA_BLOB db_key_blob;
3140 0 : bool pw_equal;
3141 :
3142 626 : if (io->n.cleartext_utf8 == NULL) {
3143 : /*
3144 : * No point checking history if we don't have
3145 : * a cleartext password.
3146 : */
3147 266 : break;
3148 : }
3149 :
3150 626 : if (io->ac->search_res == NULL) {
3151 : /*
3152 : * This is an ADD, no existing history to check
3153 : */
3154 0 : break;
3155 : }
3156 :
3157 : /*
3158 : * If this account requires a smartcard for login, we don't
3159 : * attempt a comparison with the old password.
3160 : */
3161 626 : if (io->u.userAccountControl & UF_SMARTCARD_REQUIRED) {
3162 0 : break;
3163 : }
3164 :
3165 : /*
3166 : * Extract the old ENCTYPE_AES256_CTS_HMAC_SHA1_96 value from
3167 : * the supplementalCredentials.
3168 : */
3169 626 : krb5_ret = dsdb_extract_aes_256_key(io->smb_krb5_context->krb5_context,
3170 626 : io->ac,
3171 : ldb,
3172 626 : io->ac->search_res->message,
3173 : io->u.userAccountControl,
3174 : &request_kvno, /* kvno */
3175 : NULL, /* kvno_out */
3176 : &db_key_blob,
3177 : NULL); /* salt */
3178 626 : if (krb5_ret == ENOENT) {
3179 : /*
3180 : * If there is no old AES hash (perhaps an imported DB with
3181 : * just unicodePwd) then we just won't have an old
3182 : * password to compare to if there is no NT hash
3183 : */
3184 266 : break;
3185 360 : } else if (krb5_ret) {
3186 0 : ldb_asprintf_errstring(ldb,
3187 : "check_password_restrictions: "
3188 : "extraction of old[%u - %d = %d] aes256-cts-hmac-sha1-96 key failed: %s",
3189 0 : io->o.kvno, i, io->o.kvno - i,
3190 0 : smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
3191 0 : krb5_ret, io->ac));
3192 8 : return LDB_ERR_OPERATIONS_ERROR;
3193 : }
3194 :
3195 : /* This is the actual history check */
3196 360 : pw_equal = data_blob_equal_const_time(&io->n.aes_256,
3197 : &db_key_blob);
3198 360 : if (pw_equal) {
3199 8 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
3200 8 : *werror = WERR_PASSWORD_RESTRICTION;
3201 8 : ldb_asprintf_errstring(ldb,
3202 : "%08X: %s - check_password_restrictions: "
3203 : "the password was already used (in history)!",
3204 : W_ERROR_V(*werror),
3205 : ldb_strerror(ret));
3206 8 : io->ac->status->reject_reason = SAM_PWD_CHANGE_PWD_IN_HISTORY;
3207 8 : return ret;
3208 : }
3209 : }
3210 :
3211 : /* are all password changes disallowed? */
3212 494 : if (io->ac->status->domain_data.pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
3213 0 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
3214 0 : *werror = WERR_PASSWORD_RESTRICTION;
3215 0 : ldb_asprintf_errstring(ldb,
3216 : "%08X: %s - check_password_restrictions: "
3217 : "password changes disabled!",
3218 : W_ERROR_V(*werror),
3219 : ldb_strerror(ret));
3220 0 : return ret;
3221 : }
3222 :
3223 : /* can this user change the password? */
3224 494 : if (io->u.userAccountControl & UF_PASSWD_CANT_CHANGE) {
3225 0 : ret = LDB_ERR_CONSTRAINT_VIOLATION;
3226 0 : *werror = WERR_PASSWORD_RESTRICTION;
3227 0 : ldb_asprintf_errstring(ldb,
3228 : "%08X: %s - check_password_restrictions: "
3229 : "password can't be changed on this account!",
3230 : W_ERROR_V(*werror),
3231 : ldb_strerror(ret));
3232 0 : return ret;
3233 : }
3234 :
3235 494 : return LDB_SUCCESS;
3236 : }
3237 :
3238 48387 : static int check_password_restrictions_and_log(struct setup_password_fields_io *io)
3239 : {
3240 360 : WERROR werror;
3241 48387 : int ret = check_password_restrictions(io, &werror);
3242 48387 : struct ph_context *ac = io->ac;
3243 : /*
3244 : * Password resets are not authentication events, and if the
3245 : * upper layer checked the password and supplied the hash
3246 : * values as proof, then this is also not an authentication
3247 : * even at this layer (already logged). This is to log LDAP
3248 : * password changes.
3249 : */
3250 :
3251 : /* Do not record a failure in the auth log below in the success case */
3252 48387 : if (ret == LDB_SUCCESS) {
3253 47424 : werror = WERR_OK;
3254 : }
3255 :
3256 48387 : if (ac->pwd_reset == false && ac->change == NULL) {
3257 1128 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3258 0 : struct imessaging_context *msg_ctx;
3259 0 : struct loadparm_context *lp_ctx
3260 1128 : = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
3261 : struct loadparm_context);
3262 1128 : NTSTATUS status = werror_to_ntstatus(werror);
3263 1128 : const char *domain_name = lpcfg_sam_name(lp_ctx);
3264 1128 : void *opaque_remote_address = NULL;
3265 : /*
3266 : * Forcing this via the NTLM auth structure is not ideal, but
3267 : * it is the most practical option right now, and ensures the
3268 : * logs are consistent, even if some elements are always NULL.
3269 : */
3270 1128 : struct auth_usersupplied_info ui = {
3271 : .was_mapped = true,
3272 : .client = {
3273 1128 : .account_name = io->u.sAMAccountName,
3274 : .domain_name = domain_name,
3275 : },
3276 : .mapped = {
3277 1128 : .account_name = io->u.sAMAccountName,
3278 : .domain_name = domain_name,
3279 : },
3280 : .service_description = "LDAP Password Change",
3281 : .auth_description = "LDAP Modify",
3282 : .password_type = "plaintext"
3283 : };
3284 :
3285 1128 : opaque_remote_address = ldb_get_opaque(ldb,
3286 : "remoteAddress");
3287 1128 : if (opaque_remote_address == NULL) {
3288 96 : ldb_asprintf_errstring(ldb,
3289 : "Failed to obtain remote address for "
3290 : "the LDAP client while changing the "
3291 : "password");
3292 96 : return LDB_ERR_OPERATIONS_ERROR;
3293 : }
3294 1032 : ui.remote_host = talloc_get_type(opaque_remote_address,
3295 : struct tsocket_address);
3296 :
3297 1032 : msg_ctx = imessaging_client_init(ac, lp_ctx,
3298 : ldb_get_event_context(ldb));
3299 1032 : if (!msg_ctx) {
3300 0 : ldb_asprintf_errstring(ldb,
3301 : "Failed to generate client messaging context in %s",
3302 : lpcfg_imessaging_path(ac, lp_ctx));
3303 0 : return LDB_ERR_OPERATIONS_ERROR;
3304 : }
3305 1032 : log_authentication_event(msg_ctx,
3306 : lp_ctx,
3307 : NULL,
3308 : &ui,
3309 : status,
3310 : domain_name,
3311 : io->u.sAMAccountName,
3312 : io->u.account_sid,
3313 : NULL /* client_audit_info */,
3314 : NULL /* server_audit_info */);
3315 :
3316 : }
3317 47931 : return ret;
3318 : }
3319 :
3320 47424 : static int update_final_msg(struct setup_password_fields_io *io)
3321 : {
3322 47424 : struct ldb_context *ldb = ldb_module_get_ctx(io->ac->module);
3323 360 : int ret;
3324 47424 : int el_flags = 0;
3325 47424 : bool update_password = io->ac->update_password;
3326 47424 : bool update_scb = io->ac->update_password;
3327 :
3328 : /*
3329 : * If we add a user without initial password,
3330 : * we need to add replication meta data for
3331 : * following attributes:
3332 : * - unicodePwd
3333 : * - dBCSPwd
3334 : * - ntPwdHistory
3335 : * - lmPwdHistory
3336 : *
3337 : * If we add a user with initial password or a
3338 : * password is changed of an existing user,
3339 : * we need to replace the following attributes
3340 : * with a forced meta data update, e.g. also
3341 : * when updating an empty attribute with an empty value:
3342 : * - unicodePwd
3343 : * - dBCSPwd
3344 : * - ntPwdHistory
3345 : * - lmPwdHistory
3346 : * - supplementalCredentials
3347 : */
3348 :
3349 47424 : switch (io->ac->req->operation) {
3350 30017 : case LDB_ADD:
3351 30017 : update_password = true;
3352 30017 : el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
3353 30017 : break;
3354 17047 : case LDB_MODIFY:
3355 17186 : el_flags |= LDB_FLAG_MOD_REPLACE;
3356 17186 : el_flags |= DSDB_FLAG_INTERNAL_FORCE_META_DATA;
3357 17186 : break;
3358 0 : default:
3359 0 : return ldb_module_operr(io->ac->module);
3360 : }
3361 :
3362 47203 : if (update_password) {
3363 47131 : ret = ldb_msg_add_empty(io->ac->update_msg,
3364 : "unicodePwd",
3365 : el_flags, NULL);
3366 47131 : if (ret != LDB_SUCCESS) {
3367 0 : return ret;
3368 : }
3369 :
3370 : /*
3371 : * This wipes any old LM password after any password
3372 : * update operation.
3373 : *
3374 : * This is the same as the previous default behaviour
3375 : * of 'lanman auth = no'
3376 : */
3377 47131 : ret = ldb_msg_add_empty(io->ac->update_msg,
3378 : "dBCSPwd",
3379 : el_flags, NULL);
3380 47131 : if (ret != LDB_SUCCESS) {
3381 0 : return ret;
3382 : }
3383 47131 : ret = ldb_msg_add_empty(io->ac->update_msg,
3384 : "ntPwdHistory",
3385 : el_flags, NULL);
3386 47131 : if (ret != LDB_SUCCESS) {
3387 0 : return ret;
3388 : }
3389 : /*
3390 : * This wipes any LM password history after any password
3391 : * update operation.
3392 : *
3393 : * This is the same as the previous default behaviour
3394 : * of 'lanman auth = no'
3395 : */
3396 47131 : ret = ldb_msg_add_empty(io->ac->update_msg,
3397 : "lmPwdHistory",
3398 : el_flags, NULL);
3399 47131 : if (ret != LDB_SUCCESS) {
3400 0 : return ret;
3401 : }
3402 : }
3403 47424 : if (update_scb) {
3404 20959 : ret = ldb_msg_add_empty(io->ac->update_msg,
3405 : "supplementalCredentials",
3406 : el_flags, NULL);
3407 20959 : if (ret != LDB_SUCCESS) {
3408 0 : return ret;
3409 : }
3410 : }
3411 47424 : if (io->ac->update_lastset) {
3412 47282 : ret = ldb_msg_add_empty(io->ac->update_msg,
3413 : "pwdLastSet",
3414 : el_flags, NULL);
3415 47282 : if (ret != LDB_SUCCESS) {
3416 0 : return ret;
3417 : }
3418 : }
3419 :
3420 47424 : if (io->g.nt_hash != NULL) {
3421 20326 : ret = samdb_msg_add_hash(ldb, io->ac,
3422 20121 : io->ac->update_msg,
3423 : "unicodePwd",
3424 19916 : io->g.nt_hash);
3425 20121 : if (ret != LDB_SUCCESS) {
3426 0 : return ret;
3427 : }
3428 : }
3429 :
3430 47424 : if (io->g.nt_history_len > 0) {
3431 20269 : ret = samdb_msg_add_hashes(ldb, io->ac,
3432 20064 : io->ac->update_msg,
3433 : "ntPwdHistory",
3434 : io->g.nt_history,
3435 : io->g.nt_history_len);
3436 20064 : if (ret != LDB_SUCCESS) {
3437 0 : return ret;
3438 : }
3439 : }
3440 47424 : if (io->g.supplemental.length > 0) {
3441 20798 : ret = ldb_msg_add_value(io->ac->update_msg,
3442 : "supplementalCredentials",
3443 20599 : &io->g.supplemental, NULL);
3444 20599 : if (ret != LDB_SUCCESS) {
3445 0 : return ret;
3446 : }
3447 : }
3448 47424 : if (io->ac->update_lastset) {
3449 47282 : ret = samdb_msg_add_uint64(ldb, io->ac,
3450 46922 : io->ac->update_msg,
3451 : "pwdLastSet",
3452 : io->g.last_set);
3453 47282 : if (ret != LDB_SUCCESS) {
3454 0 : return ret;
3455 : }
3456 : }
3457 :
3458 47064 : return LDB_SUCCESS;
3459 : }
3460 :
3461 : /*
3462 : * This is intended for use by the "password_hash" module since there
3463 : * password changes can be specified through one message element with the
3464 : * new password (to set) and another one with the old password (to unset).
3465 : *
3466 : * The first which sets a password (new value) can have flags
3467 : * (LDB_FLAG_MOD_ADD, LDB_FLAG_MOD_REPLACE) but also none (on "add" operations
3468 : * for entries). The latter (old value) has always specified
3469 : * LDB_FLAG_MOD_DELETE.
3470 : *
3471 : * Returns LDB_ERR_CONSTRAINT_VIOLATION and LDB_ERR_UNWILLING_TO_PERFORM if
3472 : * matching message elements are malformed in respect to the set/change rules.
3473 : * Otherwise it returns LDB_SUCCESS.
3474 : */
3475 198149 : static int msg_find_old_and_new_pwd_val(const struct ldb_message *msg,
3476 : const char *name,
3477 : enum ldb_request_type operation,
3478 : const struct ldb_val **new_val,
3479 : const struct ldb_val **old_val)
3480 : {
3481 1440 : unsigned int i;
3482 :
3483 198149 : *new_val = NULL;
3484 198149 : *old_val = NULL;
3485 :
3486 198149 : if (msg == NULL) {
3487 0 : return LDB_SUCCESS;
3488 : }
3489 :
3490 2747663 : for (i = 0; i < msg->num_elements; i++) {
3491 2549586 : if (ldb_attr_cmp(msg->elements[i].name, name) != 0) {
3492 2495218 : continue;
3493 : }
3494 :
3495 54368 : if ((operation == LDB_MODIFY) &&
3496 20120 : (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_DELETE)) {
3497 : /* 0 values are allowed */
3498 1811 : if (msg->elements[i].num_values == 1) {
3499 1255 : *old_val = &msg->elements[i].values[0];
3500 556 : } else if (msg->elements[i].num_values > 1) {
3501 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
3502 : }
3503 52557 : } else if ((operation == LDB_MODIFY) &&
3504 18309 : (LDB_FLAG_MOD_TYPE(msg->elements[i].flags) == LDB_FLAG_MOD_REPLACE)) {
3505 16519 : if (msg->elements[i].num_values > 0) {
3506 16483 : *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3507 : } else {
3508 36 : return LDB_ERR_UNWILLING_TO_PERFORM;
3509 : }
3510 : } else {
3511 : /* Add operations and LDB_FLAG_MOD_ADD */
3512 36038 : if (msg->elements[i].num_values > 0) {
3513 36002 : *new_val = &msg->elements[i].values[msg->elements[i].num_values - 1];
3514 : } else {
3515 36 : return LDB_ERR_CONSTRAINT_VIOLATION;
3516 : }
3517 : }
3518 : }
3519 :
3520 196637 : return LDB_SUCCESS;
3521 : }
3522 :
3523 48661 : static int setup_io(struct ph_context *ac,
3524 : const struct ldb_message *client_msg,
3525 : const struct ldb_message *existing_msg,
3526 : struct setup_password_fields_io *io)
3527 : {
3528 360 : const struct ldb_val *quoted_utf16, *old_quoted_utf16, *lm_hash, *old_lm_hash;
3529 48661 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
3530 48661 : struct loadparm_context *lp_ctx = talloc_get_type(
3531 : ldb_get_opaque(ldb, "loadparm"), struct loadparm_context);
3532 49021 : enum store_nt_hash store_hash_setting =
3533 48661 : lpcfg_nt_hash_store(lp_ctx);
3534 360 : int ret;
3535 48661 : const struct ldb_message *info_msg = NULL;
3536 48661 : struct dom_sid *account_sid = NULL;
3537 48661 : int rodc_krbtgt = 0;
3538 :
3539 48661 : *io = (struct setup_password_fields_io) {};
3540 :
3541 : /* Some operations below require kerberos contexts */
3542 :
3543 48661 : if (existing_msg != NULL) {
3544 : /*
3545 : * This is a modify operation
3546 : */
3547 18239 : info_msg = existing_msg;
3548 : } else {
3549 : /*
3550 : * This is an add operation
3551 : */
3552 30283 : info_msg = client_msg;
3553 : }
3554 :
3555 48661 : ret = smb_krb5_init_context(ac,
3556 48661 : (struct loadparm_context *)ldb_get_opaque(ldb, "loadparm"),
3557 : &io->smb_krb5_context);
3558 :
3559 48661 : if (ret != 0) {
3560 : /*
3561 : * In the special case of mit krb5.conf vs heimdal, the includedir
3562 : * statement causes ret == 22 (KRB5_CONFIG_BADFORMAT) to be returned.
3563 : * We look for this case so that we can give a more instructional
3564 : * message to the administrator.
3565 : */
3566 0 : if (ret == KRB5_CONFIG_BADFORMAT || ret == EINVAL) {
3567 0 : ldb_asprintf_errstring(ldb, "Failed to setup krb5_context: %s - "
3568 : "This could be due to an invalid krb5 configuration. "
3569 : "Please check your system's krb5 configuration is correct.",
3570 : error_message(ret));
3571 : } else {
3572 0 : ldb_asprintf_errstring(ldb, "Failed to setup krb5_context: %s",
3573 : error_message(ret));
3574 : }
3575 0 : return LDB_ERR_OPERATIONS_ERROR;
3576 : }
3577 :
3578 48661 : io->ac = ac;
3579 :
3580 48661 : io->u.userAccountControl = ldb_msg_find_attr_as_uint(info_msg,
3581 : "userAccountControl", 0);
3582 48661 : if (info_msg == existing_msg) {
3583 : /*
3584 : * We only take pwdLastSet from the existing object
3585 : * otherwise we leave it as 0.
3586 : *
3587 : * If no attribute is available, e.g. on deleted objects
3588 : * we remember that as UINT64_MAX.
3589 : */
3590 18378 : io->u.pwdLastSet = samdb_result_nttime(info_msg, "pwdLastSet",
3591 : UINT64_MAX);
3592 : }
3593 48661 : io->u.sAMAccountName = ldb_msg_find_attr_as_string(info_msg,
3594 : "sAMAccountName", NULL);
3595 48661 : io->u.user_principal_name = ldb_msg_find_attr_as_string(info_msg,
3596 : "userPrincipalName", NULL);
3597 48661 : io->u.displayName = ldb_msg_find_attr_as_string(info_msg,
3598 : "displayName", NULL);
3599 :
3600 : /* Ensure it has an objectSID too */
3601 48661 : io->u.account_sid = samdb_result_dom_sid(ac, info_msg, "objectSid");
3602 48661 : if (io->u.account_sid != NULL) {
3603 359 : NTSTATUS status;
3604 48660 : uint32_t rid = 0;
3605 :
3606 48660 : status = dom_sid_split_rid(account_sid, io->u.account_sid, NULL, &rid);
3607 48660 : if (NT_STATUS_IS_OK(status)) {
3608 48660 : if (rid == DOMAIN_RID_KRBTGT) {
3609 199 : io->u.is_krbtgt = true;
3610 : }
3611 : }
3612 : }
3613 :
3614 48661 : rodc_krbtgt = ldb_msg_find_attr_as_int(info_msg,
3615 : "msDS-SecondaryKrbTgtNumber", 0);
3616 48661 : if (rodc_krbtgt != 0) {
3617 100 : io->u.is_krbtgt = true;
3618 : }
3619 :
3620 48661 : if (io->u.sAMAccountName == NULL) {
3621 0 : ldb_asprintf_errstring(ldb,
3622 : "setup_io: sAMAccountName attribute is missing on %s for attempted password set/change",
3623 0 : ldb_dn_get_linearized(info_msg->dn));
3624 :
3625 0 : return LDB_ERR_CONSTRAINT_VIOLATION;
3626 : }
3627 :
3628 48661 : if (io->u.userAccountControl & UF_INTERDOMAIN_TRUST_ACCOUNT) {
3629 218 : struct ldb_control *permit_trust = ldb_request_get_control(ac->req,
3630 : DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID);
3631 :
3632 218 : if (permit_trust == NULL) {
3633 4 : ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
3634 4 : ldb_asprintf_errstring(ldb,
3635 : "%08X: %s - setup_io: changing the interdomain trust password "
3636 : "on %s not allowed via LDAP. Use LSA or NETLOGON",
3637 4 : W_ERROR_V(WERR_ACCESS_DENIED),
3638 : ldb_strerror(ret),
3639 4 : ldb_dn_get_linearized(info_msg->dn));
3640 4 : return ret;
3641 : }
3642 : }
3643 :
3644 : /* Only non-trust accounts have restrictions (possibly this test is the
3645 : * wrong way around, but we like to be restrictive if possible */
3646 48657 : io->u.restrictions = !(io->u.userAccountControl & UF_TRUST_ACCOUNT_MASK);
3647 :
3648 48657 : if (io->u.is_krbtgt) {
3649 299 : io->u.restrictions = 0;
3650 299 : io->ac->status->domain_data.pwdHistoryLength =
3651 299 : MAX(io->ac->status->domain_data.pwdHistoryLength, 3);
3652 : }
3653 :
3654 : /*
3655 : * Machine accounts need the NT hash to operate the NETLOGON
3656 : * ServerAuthenticate{,2,3} logic
3657 : */
3658 48657 : if (!(io->u.userAccountControl & UF_NORMAL_ACCOUNT)) {
3659 5773 : store_hash_setting = NT_HASH_STORE_ALWAYS;
3660 : }
3661 :
3662 48458 : switch (store_hash_setting) {
3663 46967 : case NT_HASH_STORE_ALWAYS:
3664 46967 : io->u.store_nt_hash = true;
3665 46967 : break;
3666 1690 : case NT_HASH_STORE_NEVER:
3667 1690 : io->u.store_nt_hash = false;
3668 1690 : break;
3669 0 : case NT_HASH_STORE_AUTO:
3670 0 : if (lpcfg_ntlm_auth(lp_ctx) == NTLM_AUTH_DISABLED) {
3671 0 : io->u.store_nt_hash = false;
3672 0 : break;
3673 : }
3674 0 : io->u.store_nt_hash = true;
3675 0 : break;
3676 : }
3677 :
3678 48657 : if (ac->userPassword) {
3679 3905 : ret = msg_find_old_and_new_pwd_val(client_msg, "userPassword",
3680 3905 : ac->req->operation,
3681 : &io->n.cleartext_utf8,
3682 : &io->og.cleartext_utf8);
3683 3905 : if (ret != LDB_SUCCESS) {
3684 18 : ldb_asprintf_errstring(ldb,
3685 : "setup_io: "
3686 : "it's only allowed to set the old password once!");
3687 18 : return ret;
3688 : }
3689 : }
3690 :
3691 48639 : if (io->n.cleartext_utf8 != NULL) {
3692 0 : struct ldb_val *cleartext_utf8_blob;
3693 0 : char *p;
3694 :
3695 1572 : cleartext_utf8_blob = talloc(io->ac, struct ldb_val);
3696 1572 : if (!cleartext_utf8_blob) {
3697 0 : return ldb_oom(ldb);
3698 : }
3699 :
3700 1572 : *cleartext_utf8_blob = *io->n.cleartext_utf8;
3701 :
3702 : /* make sure we have a null terminated string */
3703 1572 : p = talloc_strndup(cleartext_utf8_blob,
3704 1572 : (const char *)io->n.cleartext_utf8->data,
3705 1572 : io->n.cleartext_utf8->length);
3706 1572 : if ((p == NULL) && (io->n.cleartext_utf8->length > 0)) {
3707 0 : return ldb_oom(ldb);
3708 : }
3709 1572 : cleartext_utf8_blob->data = (uint8_t *)p;
3710 :
3711 1572 : io->n.cleartext_utf8 = cleartext_utf8_blob;
3712 : }
3713 :
3714 48999 : ret = msg_find_old_and_new_pwd_val(client_msg, "clearTextPassword",
3715 48639 : ac->req->operation,
3716 : &io->n.cleartext_utf16,
3717 : &io->og.cleartext_utf16);
3718 48639 : if (ret != LDB_SUCCESS) {
3719 18 : ldb_asprintf_errstring(ldb,
3720 : "setup_io: "
3721 : "it's only allowed to set the old password once!");
3722 18 : return ret;
3723 : }
3724 :
3725 : /* this rather strange looking piece of code is there to
3726 : handle a ldap client setting a password remotely using the
3727 : unicodePwd ldap field. The syntax is that the password is
3728 : in UTF-16LE, with a " at either end. Unfortunately the
3729 : unicodePwd field is also used to store the nt hashes
3730 : internally in Samba, and is used in the nt hash format on
3731 : the wire in DRS replication, so we have a single name for
3732 : two distinct values. The code below leaves us with a small
3733 : chance (less than 1 in 2^32) of a mixup, if someone manages
3734 : to create a MD4 hash which starts and ends in 0x22 0x00, as
3735 : that would then be treated as a UTF16 password rather than
3736 : a nthash */
3737 :
3738 48621 : ret = msg_find_old_and_new_pwd_val(client_msg, "unicodePwd",
3739 48261 : ac->req->operation,
3740 : "ed_utf16,
3741 : &old_quoted_utf16);
3742 48621 : if (ret != LDB_SUCCESS) {
3743 18 : ldb_asprintf_errstring(ldb,
3744 : "setup_io: "
3745 : "it's only allowed to set the old password once!");
3746 18 : return ret;
3747 : }
3748 :
3749 : /* Checks and converts the actual "unicodePwd" attribute */
3750 48603 : if (!ac->hash_values &&
3751 17524 : quoted_utf16 &&
3752 17524 : quoted_utf16->length >= 4 &&
3753 17524 : quoted_utf16->data[0] == '"' &&
3754 17506 : quoted_utf16->data[1] == 0 &&
3755 17506 : quoted_utf16->data[quoted_utf16->length-2] == '"' &&
3756 17506 : quoted_utf16->data[quoted_utf16->length-1] == 0) {
3757 32 : struct ldb_val *quoted_utf16_2;
3758 :
3759 17506 : if (io->n.cleartext_utf16) {
3760 : /* refuse the change if someone wants to change with
3761 : both UTF16 possibilities at the same time... */
3762 0 : ldb_asprintf_errstring(ldb,
3763 : "setup_io: "
3764 : "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3765 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
3766 : }
3767 :
3768 : /*
3769 : * adapt the quoted UTF16 string to be a real
3770 : * cleartext one
3771 : */
3772 17506 : quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3773 17506 : if (quoted_utf16_2 == NULL) {
3774 0 : return ldb_oom(ldb);
3775 : }
3776 :
3777 17506 : quoted_utf16_2->data = quoted_utf16->data + 2;
3778 17506 : quoted_utf16_2->length = quoted_utf16->length-4;
3779 17506 : io->n.cleartext_utf16 = quoted_utf16_2;
3780 17506 : io->n.nt_hash = NULL;
3781 :
3782 31097 : } else if (quoted_utf16) {
3783 : /* We have only the hash available -> so no plaintext here */
3784 378 : if (!ac->hash_values) {
3785 : /* refuse the change if someone wants to change
3786 : the hash without control specified... */
3787 18 : ldb_asprintf_errstring(ldb,
3788 : "setup_io: "
3789 : "it's not allowed to set the NT hash password directly'");
3790 : /* this looks odd but this is what Windows does:
3791 : returns "UNWILLING_TO_PERFORM" on wrong
3792 : password sets and "CONSTRAINT_VIOLATION" on
3793 : wrong password changes. */
3794 18 : if (old_quoted_utf16 == NULL) {
3795 9 : return LDB_ERR_UNWILLING_TO_PERFORM;
3796 : }
3797 :
3798 9 : return LDB_ERR_CONSTRAINT_VIOLATION;
3799 : }
3800 :
3801 360 : io->n.nt_hash = talloc(io->ac, struct samr_Password);
3802 360 : if (io->n.nt_hash == NULL) {
3803 0 : return ldb_oom(ldb);
3804 : }
3805 720 : memcpy(io->n.nt_hash->hash, quoted_utf16->data,
3806 360 : MIN(quoted_utf16->length, sizeof(io->n.nt_hash->hash)));
3807 : }
3808 :
3809 : /* Checks and converts the previous "unicodePwd" attribute */
3810 48585 : if (!ac->hash_values &&
3811 238 : old_quoted_utf16 &&
3812 238 : old_quoted_utf16->length >= 4 &&
3813 238 : old_quoted_utf16->data[0] == '"' &&
3814 238 : old_quoted_utf16->data[1] == 0 &&
3815 238 : old_quoted_utf16->data[old_quoted_utf16->length-2] == '"' &&
3816 238 : old_quoted_utf16->data[old_quoted_utf16->length-1] == 0) {
3817 0 : struct ldb_val *old_quoted_utf16_2;
3818 :
3819 238 : if (io->og.cleartext_utf16) {
3820 : /* refuse the change if someone wants to change with
3821 : both UTF16 possibilities at the same time... */
3822 0 : ldb_asprintf_errstring(ldb,
3823 : "setup_io: "
3824 : "it's only allowed to set the cleartext password as 'unicodePwd' or as 'clearTextPassword'");
3825 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
3826 : }
3827 :
3828 : /*
3829 : * adapt the quoted UTF16 string to be a real
3830 : * cleartext one
3831 : */
3832 238 : old_quoted_utf16_2 = talloc(io->ac, struct ldb_val);
3833 238 : if (old_quoted_utf16_2 == NULL) {
3834 0 : return ldb_oom(ldb);
3835 : }
3836 :
3837 238 : old_quoted_utf16_2->data = old_quoted_utf16->data + 2;
3838 238 : old_quoted_utf16_2->length = old_quoted_utf16->length-4;
3839 :
3840 238 : io->og.cleartext_utf16 = old_quoted_utf16_2;
3841 238 : io->og.nt_hash = NULL;
3842 48347 : } else if (old_quoted_utf16) {
3843 : /* We have only the hash available -> so no plaintext here */
3844 0 : if (!ac->hash_values) {
3845 : /* refuse the change if someone wants to change
3846 : the hash without control specified... */
3847 0 : ldb_asprintf_errstring(ldb,
3848 : "setup_io: "
3849 : "it's not allowed to set the NT hash password directly'");
3850 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
3851 : }
3852 :
3853 0 : io->og.nt_hash = talloc(io->ac, struct samr_Password);
3854 0 : if (io->og.nt_hash == NULL) {
3855 0 : return ldb_oom(ldb);
3856 : }
3857 360 : memcpy(io->og.nt_hash->hash, old_quoted_utf16->data,
3858 0 : MIN(old_quoted_utf16->length, sizeof(io->og.nt_hash->hash)));
3859 : }
3860 :
3861 : /* Handles the "dBCSPwd" attribute (LM hash) */
3862 48945 : ret = msg_find_old_and_new_pwd_val(client_msg, "dBCSPwd",
3863 48585 : ac->req->operation,
3864 : &lm_hash, &old_lm_hash);
3865 48585 : if (ret != LDB_SUCCESS) {
3866 18 : ldb_asprintf_errstring(ldb,
3867 : "setup_io: "
3868 : "it's only allowed to set the old password once!");
3869 18 : return ret;
3870 : }
3871 :
3872 48567 : if (((lm_hash != NULL) || (old_lm_hash != NULL))) {
3873 : /* refuse the change if someone wants to change the LM hash */
3874 27 : ldb_asprintf_errstring(ldb,
3875 : "setup_io: "
3876 : "it's not allowed to set the LM hash password (dBCSPwd)'");
3877 27 : return LDB_ERR_UNWILLING_TO_PERFORM;
3878 : }
3879 :
3880 : /*
3881 : * Handles the password change control if it's specified. It has the
3882 : * precedence and overrides already specified old password values of
3883 : * change requests (but that shouldn't happen since the control is
3884 : * fully internal and only used in conjunction with replace requests!).
3885 : */
3886 48540 : if (ac->change != NULL) {
3887 883 : io->og.nt_hash = NULL;
3888 : }
3889 :
3890 : /* refuse the change if someone wants to change the clear-
3891 : text and supply his own hashes at the same time... */
3892 48540 : if ((io->n.cleartext_utf8 || io->n.cleartext_utf16)
3893 21611 : && (io->n.nt_hash)) {
3894 0 : ldb_asprintf_errstring(ldb,
3895 : "setup_io: "
3896 : "it's only allowed to set the password in form of cleartext attributes or as hashes");
3897 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
3898 : }
3899 :
3900 : /* refuse the change if someone wants to change the password
3901 : using both plaintext methods (UTF8 and UTF16) at the same time... */
3902 48540 : if (io->n.cleartext_utf8 && io->n.cleartext_utf16) {
3903 0 : ldb_asprintf_errstring(ldb,
3904 : "setup_io: "
3905 : "it's only allowed to set the cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3906 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
3907 : }
3908 :
3909 : /* refuse the change if someone tries to set/change the password by
3910 : * any method that would leave us without a password! */
3911 48540 : if (io->ac->update_password
3912 22043 : && (!io->n.cleartext_utf8) && (!io->n.cleartext_utf16)
3913 432 : && (!io->n.nt_hash)) {
3914 72 : ldb_asprintf_errstring(ldb,
3915 : "setup_io: "
3916 : "It's not possible to delete the password (changes using the LAN Manager hash alone could be deactivated)!");
3917 : /* on "userPassword" and "clearTextPassword" we've to return
3918 : * something different, since these are virtual attributes */
3919 99 : if ((ldb_msg_find_element(client_msg, "userPassword") != NULL) ||
3920 27 : (ldb_msg_find_element(client_msg, "clearTextPassword") != NULL)) {
3921 54 : return LDB_ERR_CONSTRAINT_VIOLATION;
3922 : }
3923 18 : return LDB_ERR_UNWILLING_TO_PERFORM;
3924 : }
3925 :
3926 : /*
3927 : * refuse the change if someone wants to compare against a
3928 : * plaintext or dsdb_control_password_change at the same time
3929 : * for a "password modify" operation...
3930 : */
3931 48468 : if ((io->og.cleartext_utf8 || io->og.cleartext_utf16)
3932 1192 : && ac->change) {
3933 0 : ldb_asprintf_errstring(ldb,
3934 : "setup_io: "
3935 : "it's only allowed to provide the old password in form of cleartext attributes or as the dsdb_control_password_change");
3936 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
3937 : }
3938 :
3939 : /* refuse the change if someone wants to compare against both
3940 : * plaintexts at the same time for a "password modify" operation... */
3941 48468 : if (io->og.cleartext_utf8 && io->og.cleartext_utf16) {
3942 0 : ldb_asprintf_errstring(ldb,
3943 : "setup_io: "
3944 : "it's only allowed to provide the old cleartext password as 'unicodePwd' or as 'userPassword' or as 'clearTextPassword'");
3945 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
3946 : }
3947 :
3948 : /* Decides if we have a password modify or password reset operation */
3949 48468 : if (ac->req->operation == LDB_ADD) {
3950 : /* On "add" we have only "password reset" */
3951 30247 : ac->pwd_reset = true;
3952 18221 : } else if (ac->req->operation == LDB_MODIFY) {
3953 18221 : struct ldb_control *pav_ctrl = NULL;
3954 18221 : struct dsdb_control_password_acl_validation *pav = NULL;
3955 :
3956 18221 : pav_ctrl = ldb_request_get_control(ac->req,
3957 : DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID);
3958 18221 : if (pav_ctrl != NULL) {
3959 16493 : pav = talloc_get_type_abort(pav_ctrl->data,
3960 : struct dsdb_control_password_acl_validation);
3961 : }
3962 :
3963 18221 : if (pav == NULL && ac->update_password) {
3964 65 : bool ok;
3965 :
3966 : /*
3967 : * If the DSDB_CONTROL_PASSWORD_ACL_VALIDATION_OID
3968 : * control is missing, we require system access!
3969 : */
3970 1415 : ok = dsdb_have_system_access(
3971 : ac->module,
3972 : ac->req,
3973 : SYSTEM_CONTROL_KEEP_CRITICAL);
3974 1415 : if (!ok) {
3975 0 : return ldb_module_operr(ac->module);
3976 : }
3977 : }
3978 :
3979 18221 : if (pav != NULL) {
3980 : /*
3981 : * We assume what the acl module has validated.
3982 : */
3983 16493 : ac->pwd_reset = pav->pwd_reset;
3984 1728 : } else if (io->og.cleartext_utf8 || io->og.cleartext_utf16
3985 1632 : || ac->change) {
3986 : /*
3987 : * If we have an old password specified or the
3988 : * dsdb_control_password_change then for sure
3989 : * it is a user "password change"
3990 : */
3991 457 : ac->pwd_reset = false;
3992 : } else {
3993 : /* Otherwise we have also here a "password reset" */
3994 1271 : ac->pwd_reset = true;
3995 : }
3996 : } else {
3997 : /* this shouldn't happen */
3998 0 : return ldb_operr(ldb);
3999 : }
4000 :
4001 48468 : if (existing_msg != NULL) {
4002 139 : NTSTATUS status;
4003 139 : krb5_error_code krb5_ret;
4004 139 : DATA_BLOB key_blob;
4005 139 : DATA_BLOB salt_blob;
4006 139 : uint32_t kvno;
4007 :
4008 18221 : if (ac->pwd_reset) {
4009 : /* Get the old password from the database */
4010 16146 : status = samdb_result_passwords_no_lockout(ac,
4011 : lp_ctx,
4012 : existing_msg,
4013 : &io->o.nt_hash);
4014 : } else {
4015 : /* Get the old password from the database */
4016 2075 : status = samdb_result_passwords(ac,
4017 : lp_ctx,
4018 : existing_msg,
4019 : &io->o.nt_hash);
4020 : }
4021 :
4022 18221 : if (NT_STATUS_EQUAL(status, NT_STATUS_ACCOUNT_LOCKED_OUT)) {
4023 64 : return dsdb_module_werror(ac->module,
4024 : LDB_ERR_CONSTRAINT_VIOLATION,
4025 : WERR_ACCOUNT_LOCKED_OUT,
4026 : "Password change not permitted,"
4027 : " account locked out!");
4028 : }
4029 :
4030 18157 : if (!NT_STATUS_IS_OK(status)) {
4031 : /*
4032 : * This only happens if the database has gone weird,
4033 : * not if we are just missing the passwords
4034 : */
4035 0 : return ldb_operr(ldb);
4036 : }
4037 :
4038 18157 : io->o.nt_history_len = samdb_result_hashes(ac, existing_msg,
4039 : "ntPwdHistory",
4040 : &io->o.nt_history);
4041 18157 : io->o.supplemental = ldb_msg_find_ldb_val(existing_msg,
4042 : "supplementalCredentials");
4043 :
4044 18157 : if (io->o.supplemental != NULL) {
4045 37 : enum ndr_err_code ndr_err;
4046 :
4047 2792 : ndr_err = ndr_pull_struct_blob_all(io->o.supplemental, io->ac,
4048 2755 : &io->o.scb,
4049 : (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
4050 2755 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
4051 0 : status = ndr_map_error2ntstatus(ndr_err);
4052 0 : ldb_asprintf_errstring(ldb,
4053 : "setup_io: failed to pull "
4054 : "old supplementalCredentialsBlob: %s",
4055 : nt_errstr(status));
4056 0 : return LDB_ERR_OPERATIONS_ERROR;
4057 : }
4058 : }
4059 :
4060 : /*
4061 : * If this account requires a smartcard for login, we don't
4062 : * attempt a comparison with the old password.
4063 : */
4064 18157 : if (io->u.userAccountControl & UF_SMARTCARD_REQUIRED) {
4065 14 : return LDB_SUCCESS;
4066 : }
4067 :
4068 : /*
4069 : * Extract the old ENCTYPE_AES256_CTS_HMAC_SHA1_96
4070 : * value from the supplementalCredentials.
4071 : */
4072 18282 : krb5_ret = dsdb_extract_aes_256_key(io->smb_krb5_context->krb5_context,
4073 18143 : io->ac,
4074 : ldb,
4075 : existing_msg,
4076 : io->u.userAccountControl,
4077 : NULL, /* kvno */
4078 : &kvno, /* kvno_out */
4079 : &key_blob,
4080 : &salt_blob);
4081 18143 : if (krb5_ret == ENOENT) {
4082 : /*
4083 : * If there is no old AES hash (perhaps an imported DB with
4084 : * just unicodePwd) then we just won't have an old
4085 : * password to compare to if there is no NT hash
4086 : */
4087 15394 : return LDB_SUCCESS;
4088 : }
4089 2647 : if (krb5_ret) {
4090 0 : ldb_asprintf_errstring(ldb,
4091 : "setup_io: "
4092 : "extraction of salt for old aes256-cts-hmac-sha1-96 key failed: %s",
4093 0 : smb_get_krb5_error_message(io->smb_krb5_context->krb5_context,
4094 0 : krb5_ret, io->ac));
4095 0 : return LDB_ERR_OPERATIONS_ERROR;
4096 : }
4097 :
4098 2647 : io->o.salt = salt_blob;
4099 2647 : io->o.aes_256 = key_blob;
4100 2647 : io->o.kvno = kvno;
4101 : }
4102 :
4103 32636 : return LDB_SUCCESS;
4104 : }
4105 :
4106 49010 : static struct ph_context *ph_init_context(struct ldb_module *module,
4107 : struct ldb_request *req,
4108 : bool userPassword,
4109 : bool update_password)
4110 : {
4111 360 : struct ldb_context *ldb;
4112 360 : struct ph_context *ac;
4113 49010 : struct loadparm_context *lp_ctx = NULL;
4114 :
4115 49010 : ldb = ldb_module_get_ctx(module);
4116 :
4117 49010 : ac = talloc_zero(req, struct ph_context);
4118 49010 : if (ac == NULL) {
4119 0 : ldb_set_errstring(ldb, "Out of Memory");
4120 0 : return NULL;
4121 : }
4122 :
4123 49010 : ac->module = module;
4124 49010 : ac->req = req;
4125 49010 : ac->userPassword = userPassword;
4126 49010 : ac->update_password = update_password;
4127 49010 : ac->update_lastset = true;
4128 :
4129 49010 : lp_ctx = talloc_get_type_abort(ldb_get_opaque(ldb, "loadparm"),
4130 : struct loadparm_context);
4131 49010 : ac->gpg_key_ids = lpcfg_password_hash_gpg_key_ids(lp_ctx);
4132 360 : ac->userPassword_schemes
4133 49010 : = lpcfg_password_hash_userpassword_schemes(lp_ctx);
4134 49010 : return ac;
4135 : }
4136 :
4137 49010 : static void ph_apply_controls(struct ph_context *ac)
4138 : {
4139 360 : struct ldb_control *ctrl;
4140 :
4141 49010 : ac->change_status = false;
4142 49010 : ctrl = ldb_request_get_control(ac->req,
4143 : DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID);
4144 49010 : if (ctrl != NULL) {
4145 2108 : ac->change_status = true;
4146 :
4147 : /* Mark the "change status" control as uncritical (done) */
4148 2108 : ctrl->critical = false;
4149 : }
4150 :
4151 49010 : ac->hash_values = false;
4152 49010 : ctrl = ldb_request_get_control(ac->req,
4153 : DSDB_CONTROL_PASSWORD_HASH_VALUES_OID);
4154 49010 : if (ctrl != NULL) {
4155 360 : ac->hash_values = true;
4156 :
4157 : /* Mark the "hash values" control as uncritical (done) */
4158 360 : ctrl->critical = false;
4159 : }
4160 :
4161 49010 : ctrl = ldb_request_get_control(ac->req,
4162 : DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID);
4163 49010 : if (ctrl != NULL) {
4164 883 : ac->change = talloc_get_type_abort(ctrl->data, struct dsdb_control_password_change);
4165 :
4166 : /* Mark the "change" control as uncritical (done) */
4167 883 : ctrl->critical = false;
4168 : }
4169 :
4170 49010 : ac->pwd_last_set_bypass = false;
4171 49010 : ctrl = ldb_request_get_control(ac->req,
4172 : DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID);
4173 49010 : if (ctrl != NULL) {
4174 5 : ac->pwd_last_set_bypass = true;
4175 :
4176 : /* Mark the "bypass pwdLastSet" control as uncritical (done) */
4177 5 : ctrl->critical = false;
4178 : }
4179 :
4180 49010 : ac->pwd_last_set_default = false;
4181 49010 : ctrl = ldb_request_get_control(ac->req,
4182 : DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID);
4183 49010 : if (ctrl != NULL) {
4184 30317 : ac->pwd_last_set_default = true;
4185 :
4186 : /* Mark the "bypass pwdLastSet" control as uncritical (done) */
4187 30317 : ctrl->critical = false;
4188 : }
4189 :
4190 49010 : ac->smartcard_reset = false;
4191 49010 : ctrl = ldb_request_get_control(ac->req,
4192 : DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
4193 49010 : if (ctrl != NULL) {
4194 30300 : struct dsdb_control_password_user_account_control *uac = NULL;
4195 30300 : uint32_t added_flags = 0;
4196 :
4197 30300 : uac = talloc_get_type_abort(ctrl->data,
4198 : struct dsdb_control_password_user_account_control);
4199 :
4200 30300 : added_flags = uac->new_flags & ~uac->old_flags;
4201 :
4202 30300 : if (added_flags & UF_SMARTCARD_REQUIRED) {
4203 23 : ac->smartcard_reset = true;
4204 : }
4205 :
4206 : /* Mark the "smartcard required" control as uncritical (done) */
4207 30300 : ctrl->critical = false;
4208 : }
4209 49010 : }
4210 :
4211 47424 : static int ph_op_callback(struct ldb_request *req, struct ldb_reply *ares)
4212 : {
4213 360 : struct ph_context *ac;
4214 :
4215 47424 : ac = talloc_get_type(req->context, struct ph_context);
4216 :
4217 47424 : if (!ares) {
4218 0 : return ldb_module_done(ac->req, NULL, NULL,
4219 : LDB_ERR_OPERATIONS_ERROR);
4220 : }
4221 :
4222 47424 : if (ares->type == LDB_REPLY_REFERRAL) {
4223 0 : return ldb_module_send_referral(ac->req, ares->referral);
4224 : }
4225 :
4226 47424 : if ((ares->error != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
4227 : /* On success and trivial errors a status control is being
4228 : * added (used for example by the "samdb_set_password" call) */
4229 1920 : ldb_reply_add_control(ares,
4230 : DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
4231 : false,
4232 1920 : ac->status);
4233 : }
4234 :
4235 47424 : if (ares->error != LDB_SUCCESS) {
4236 79 : return ldb_module_done(ac->req, ares->controls,
4237 : ares->response, ares->error);
4238 : }
4239 :
4240 47345 : if (ares->type != LDB_REPLY_DONE) {
4241 0 : talloc_free(ares);
4242 0 : return ldb_module_done(ac->req, NULL, NULL,
4243 : LDB_ERR_OPERATIONS_ERROR);
4244 : }
4245 :
4246 47345 : return ldb_module_done(ac->req, ares->controls,
4247 : ares->response, ares->error);
4248 : }
4249 :
4250 : static int password_hash_add_do_add(struct ph_context *ac);
4251 : static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares);
4252 : static int password_hash_mod_search_self(struct ph_context *ac);
4253 : static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares);
4254 : static int password_hash_mod_do_mod(struct ph_context *ac);
4255 :
4256 : /*
4257 : * LDB callback handler for searching for a user's PSO. Once we have all the
4258 : * Password Settings that apply to the user, we can continue with the modify
4259 : * operation
4260 : */
4261 638 : static int get_pso_data_callback(struct ldb_request *req,
4262 : struct ldb_reply *ares)
4263 : {
4264 638 : struct ldb_context *ldb = NULL;
4265 638 : struct ph_context *ac = NULL;
4266 638 : bool domain_complexity = true;
4267 638 : bool pso_complexity = true;
4268 638 : struct dsdb_user_pwd_settings *settings = NULL;
4269 638 : int ret = LDB_SUCCESS;
4270 :
4271 638 : ac = talloc_get_type(req->context, struct ph_context);
4272 638 : ldb = ldb_module_get_ctx(ac->module);
4273 :
4274 638 : if (!ares) {
4275 0 : ret = LDB_ERR_OPERATIONS_ERROR;
4276 0 : goto done;
4277 : }
4278 638 : if (ares->error != LDB_SUCCESS) {
4279 0 : return ldb_module_done(ac->req, ares->controls,
4280 : ares->response, ares->error);
4281 : }
4282 :
4283 638 : switch (ares->type) {
4284 319 : case LDB_REPLY_ENTRY:
4285 :
4286 : /* check status was initialized by the domain query */
4287 319 : if (ac->status == NULL) {
4288 0 : talloc_free(ares);
4289 0 : ldb_set_errstring(ldb, "Uninitialized status");
4290 0 : ret = LDB_ERR_OPERATIONS_ERROR;
4291 0 : goto done;
4292 : }
4293 :
4294 : /*
4295 : * use the PSO's values instead of the domain defaults (the PSO
4296 : * attributes should always exist, but use the domain default
4297 : * values as a fallback).
4298 : */
4299 319 : settings = &ac->status->domain_data;
4300 319 : settings->store_cleartext =
4301 638 : ldb_msg_find_attr_as_bool(ares->message,
4302 : "msDS-PasswordReversibleEncryptionEnabled",
4303 319 : settings->store_cleartext);
4304 :
4305 319 : settings->pwdHistoryLength =
4306 319 : ldb_msg_find_attr_as_uint(ares->message,
4307 : "msDS-PasswordHistoryLength",
4308 : settings->pwdHistoryLength);
4309 319 : settings->maxPwdAge =
4310 319 : ldb_msg_find_attr_as_int64(ares->message,
4311 : "msDS-MaximumPasswordAge",
4312 : settings->maxPwdAge);
4313 319 : settings->minPwdAge =
4314 319 : ldb_msg_find_attr_as_int64(ares->message,
4315 : "msDS-MinimumPasswordAge",
4316 : settings->minPwdAge);
4317 319 : settings->minPwdLength =
4318 319 : ldb_msg_find_attr_as_uint(ares->message,
4319 : "msDS-MinimumPasswordLength",
4320 : settings->minPwdLength);
4321 319 : domain_complexity =
4322 319 : (settings->pwdProperties & DOMAIN_PASSWORD_COMPLEX);
4323 319 : pso_complexity =
4324 319 : ldb_msg_find_attr_as_bool(ares->message,
4325 : "msDS-PasswordComplexityEnabled",
4326 : domain_complexity);
4327 :
4328 : /* set or clear the complexity bit if required */
4329 319 : if (pso_complexity && !domain_complexity) {
4330 0 : settings->pwdProperties |= DOMAIN_PASSWORD_COMPLEX;
4331 319 : } else if (domain_complexity && !pso_complexity) {
4332 107 : settings->pwdProperties &= ~DOMAIN_PASSWORD_COMPLEX;
4333 : }
4334 :
4335 319 : if (ac->pso_res != NULL) {
4336 0 : DBG_ERR("Too many PSO results for %s\n",
4337 : ldb_dn_get_linearized(ac->search_res->message->dn));
4338 0 : talloc_free(ac->pso_res);
4339 : }
4340 :
4341 : /* store the PSO result (we may need its lockout settings) */
4342 319 : ac->pso_res = talloc_steal(ac, ares);
4343 319 : ret = LDB_SUCCESS;
4344 319 : break;
4345 :
4346 0 : case LDB_REPLY_REFERRAL:
4347 : /* ignore */
4348 0 : talloc_free(ares);
4349 0 : ret = LDB_SUCCESS;
4350 0 : break;
4351 :
4352 319 : case LDB_REPLY_DONE:
4353 319 : talloc_free(ares);
4354 :
4355 : /*
4356 : * perform the next step of the modify operation (this code
4357 : * shouldn't get called in the 'user add' case)
4358 : */
4359 319 : if (ac->req->operation == LDB_MODIFY) {
4360 319 : ret = password_hash_mod_do_mod(ac);
4361 : } else {
4362 0 : ret = LDB_ERR_OPERATIONS_ERROR;
4363 : }
4364 319 : break;
4365 : }
4366 :
4367 638 : done:
4368 638 : if (ret != LDB_SUCCESS) {
4369 0 : struct ldb_reply *new_ares;
4370 :
4371 241 : new_ares = talloc_zero(ac->req, struct ldb_reply);
4372 241 : if (new_ares == NULL) {
4373 0 : ldb_oom(ldb);
4374 0 : return ldb_module_done(ac->req, NULL, NULL,
4375 : LDB_ERR_OPERATIONS_ERROR);
4376 : }
4377 :
4378 241 : new_ares->error = ret;
4379 241 : if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
4380 : /* On success and trivial errors a status control is being
4381 : * added (used for example by the "samdb_set_password" call) */
4382 0 : ldb_reply_add_control(new_ares,
4383 : DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
4384 : false,
4385 0 : ac->status);
4386 : }
4387 :
4388 241 : return ldb_module_done(ac->req, new_ares->controls,
4389 : new_ares->response, new_ares->error);
4390 : }
4391 :
4392 397 : return LDB_SUCCESS;
4393 : }
4394 :
4395 : /*
4396 : * Builds and returns a search request to look up the PSO that applies to
4397 : * the user in question. Returns NULL if no PSO applies, or could not be found
4398 : */
4399 18378 : static struct ldb_request * build_pso_data_request(struct ph_context *ac)
4400 : {
4401 : /* attrs[] is returned from this function in
4402 : pso_req->op.search.attrs, so it must be static, as
4403 : otherwise the compiler can put it on the stack */
4404 139 : static const char * const attrs[] = { "msDS-PasswordComplexityEnabled",
4405 : "msDS-PasswordReversibleEncryptionEnabled",
4406 : "msDS-PasswordHistoryLength",
4407 : "msDS-MaximumPasswordAge",
4408 : "msDS-MinimumPasswordAge",
4409 : "msDS-MinimumPasswordLength",
4410 : "msDS-LockoutThreshold",
4411 : "msDS-LockoutObservationWindow",
4412 : NULL };
4413 18378 : struct ldb_context *ldb = NULL;
4414 18378 : struct ldb_request *pso_req = NULL;
4415 18378 : struct ldb_dn *pso_dn = NULL;
4416 18378 : TALLOC_CTX *mem_ctx = ac;
4417 139 : int ret;
4418 :
4419 18378 : ldb = ldb_module_get_ctx(ac->module);
4420 :
4421 : /* if a PSO applies to the user, we need to lookup the PSO as well */
4422 18378 : pso_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, ac->search_res->message,
4423 : "msDS-ResultantPSO");
4424 18378 : if (pso_dn == NULL) {
4425 17920 : return NULL;
4426 : }
4427 :
4428 319 : ret = ldb_build_search_req(&pso_req, ldb, mem_ctx, pso_dn,
4429 : LDB_SCOPE_BASE, NULL, attrs, NULL,
4430 : ac, get_pso_data_callback,
4431 : ac->dom_req);
4432 :
4433 : /* log errors, but continue with the default domain settings */
4434 319 : if (ret != LDB_SUCCESS) {
4435 0 : DBG_ERR("Error %d constructing PSO query for user %s\n", ret,
4436 : ldb_dn_get_linearized(ac->search_res->message->dn));
4437 : }
4438 319 : LDB_REQ_SET_LOCATION(pso_req);
4439 319 : return pso_req;
4440 : }
4441 :
4442 :
4443 97322 : static int get_domain_data_callback(struct ldb_request *req,
4444 : struct ldb_reply *ares)
4445 : {
4446 720 : struct ldb_context *ldb;
4447 720 : struct ph_context *ac;
4448 720 : struct loadparm_context *lp_ctx;
4449 97322 : struct ldb_request *pso_req = NULL;
4450 97322 : int ret = LDB_SUCCESS;
4451 :
4452 97322 : ac = talloc_get_type(req->context, struct ph_context);
4453 97322 : ldb = ldb_module_get_ctx(ac->module);
4454 :
4455 97322 : if (!ares) {
4456 0 : ret = LDB_ERR_OPERATIONS_ERROR;
4457 0 : goto done;
4458 : }
4459 97322 : if (ares->error != LDB_SUCCESS) {
4460 0 : return ldb_module_done(ac->req, ares->controls,
4461 : ares->response, ares->error);
4462 : }
4463 :
4464 97322 : switch (ares->type) {
4465 48661 : case LDB_REPLY_ENTRY:
4466 48661 : if (ac->status != NULL) {
4467 0 : talloc_free(ares);
4468 :
4469 0 : ldb_set_errstring(ldb, "Too many results");
4470 0 : ret = LDB_ERR_OPERATIONS_ERROR;
4471 0 : goto done;
4472 : }
4473 :
4474 : /* Setup the "status" structure (used as control later) */
4475 48661 : ac->status = talloc_zero(ac->req,
4476 : struct dsdb_control_password_change_status);
4477 48661 : if (ac->status == NULL) {
4478 0 : talloc_free(ares);
4479 :
4480 0 : ldb_oom(ldb);
4481 0 : ret = LDB_ERR_OPERATIONS_ERROR;
4482 0 : goto done;
4483 : }
4484 :
4485 : /* Setup the "domain data" structure */
4486 97322 : ac->status->domain_data.pwdProperties =
4487 48661 : ldb_msg_find_attr_as_uint(ares->message, "pwdProperties", -1);
4488 97322 : ac->status->domain_data.pwdHistoryLength =
4489 48661 : ldb_msg_find_attr_as_uint(ares->message, "pwdHistoryLength", -1);
4490 97322 : ac->status->domain_data.maxPwdAge =
4491 48661 : ldb_msg_find_attr_as_int64(ares->message, "maxPwdAge", -1);
4492 97322 : ac->status->domain_data.minPwdAge =
4493 48661 : ldb_msg_find_attr_as_int64(ares->message, "minPwdAge", -1);
4494 97322 : ac->status->domain_data.minPwdLength =
4495 48661 : ldb_msg_find_attr_as_uint(ares->message, "minPwdLength", -1);
4496 48661 : ac->status->domain_data.store_cleartext =
4497 48661 : ac->status->domain_data.pwdProperties & DOMAIN_PASSWORD_STORE_CLEARTEXT;
4498 :
4499 : /* For a domain DN, this puts things in dotted notation */
4500 : /* For builtin domains, this will give details for the host,
4501 : * but that doesn't really matter, as it's just used for salt
4502 : * and kerberos principals, which don't exist here */
4503 :
4504 48661 : lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
4505 : struct loadparm_context);
4506 :
4507 48661 : ac->status->domain_data.dns_domain = lpcfg_dnsdomain(lp_ctx);
4508 48661 : ac->status->domain_data.realm = lpcfg_realm(lp_ctx);
4509 48661 : ac->status->domain_data.netbios_domain = lpcfg_sam_name(lp_ctx);
4510 :
4511 48661 : ac->status->reject_reason = SAM_PWD_CHANGE_NO_ERROR;
4512 :
4513 48661 : if (ac->dom_res != NULL) {
4514 0 : talloc_free(ares);
4515 :
4516 0 : ldb_set_errstring(ldb, "Too many results");
4517 0 : ret = LDB_ERR_OPERATIONS_ERROR;
4518 0 : goto done;
4519 : }
4520 :
4521 48661 : ac->dom_res = talloc_steal(ac, ares);
4522 48661 : ret = LDB_SUCCESS;
4523 48661 : break;
4524 :
4525 0 : case LDB_REPLY_REFERRAL:
4526 : /* ignore */
4527 0 : talloc_free(ares);
4528 0 : ret = LDB_SUCCESS;
4529 0 : break;
4530 :
4531 48661 : case LDB_REPLY_DONE:
4532 48661 : talloc_free(ares);
4533 : /* call the next step */
4534 48661 : switch (ac->req->operation) {
4535 30283 : case LDB_ADD:
4536 30283 : ret = password_hash_add_do_add(ac);
4537 30283 : break;
4538 :
4539 18378 : case LDB_MODIFY:
4540 :
4541 : /*
4542 : * The user may have an optional PSO applied. If so,
4543 : * query the PSO to get the Fine-Grained Password Policy
4544 : * for the user, before we perform the modify
4545 : */
4546 18378 : pso_req = build_pso_data_request(ac);
4547 18378 : if (pso_req != NULL) {
4548 319 : ret = ldb_next_request(ac->module, pso_req);
4549 : } else {
4550 :
4551 : /* no PSO, so we can perform the modify now */
4552 18059 : ret = password_hash_mod_do_mod(ac);
4553 : }
4554 18239 : break;
4555 :
4556 0 : default:
4557 0 : ret = LDB_ERR_OPERATIONS_ERROR;
4558 0 : break;
4559 : }
4560 48301 : break;
4561 : }
4562 :
4563 96962 : done:
4564 97322 : if (ret != LDB_SUCCESS) {
4565 0 : struct ldb_reply *new_ares;
4566 :
4567 1008 : new_ares = talloc_zero(ac->req, struct ldb_reply);
4568 1008 : if (new_ares == NULL) {
4569 0 : ldb_oom(ldb);
4570 0 : return ldb_module_done(ac->req, NULL, NULL,
4571 : LDB_ERR_OPERATIONS_ERROR);
4572 : }
4573 :
4574 1008 : new_ares->error = ret;
4575 1008 : if ((ret != LDB_ERR_OPERATIONS_ERROR) && (ac->change_status)) {
4576 : /* On success and trivial errors a status control is being
4577 : * added (used for example by the "samdb_set_password" call) */
4578 188 : ldb_reply_add_control(new_ares,
4579 : DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
4580 : false,
4581 188 : ac->status);
4582 : }
4583 :
4584 1008 : return ldb_module_done(ac->req, new_ares->controls,
4585 : new_ares->response, new_ares->error);
4586 : }
4587 :
4588 95594 : return LDB_SUCCESS;
4589 : }
4590 :
4591 48661 : static int build_domain_data_request(struct ph_context *ac)
4592 : {
4593 : /* attrs[] is returned from this function in
4594 : ac->dom_req->op.search.attrs, so it must be static, as
4595 : otherwise the compiler can put it on the stack */
4596 360 : struct ldb_context *ldb;
4597 360 : static const char * const attrs[] = { "pwdProperties",
4598 : "pwdHistoryLength",
4599 : "maxPwdAge",
4600 : "minPwdAge",
4601 : "minPwdLength",
4602 : "lockoutThreshold",
4603 : "lockOutObservationWindow",
4604 : NULL };
4605 360 : int ret;
4606 :
4607 48661 : ldb = ldb_module_get_ctx(ac->module);
4608 :
4609 48661 : ret = ldb_build_search_req(&ac->dom_req, ldb, ac,
4610 : ldb_get_default_basedn(ldb),
4611 : LDB_SCOPE_BASE,
4612 : NULL, attrs,
4613 : NULL,
4614 : ac, get_domain_data_callback,
4615 : ac->req);
4616 48661 : LDB_REQ_SET_LOCATION(ac->dom_req);
4617 48661 : return ret;
4618 : }
4619 :
4620 1197171 : static int password_hash_needed(struct ldb_module *module,
4621 : struct ldb_request *req,
4622 : struct ph_context **_ac)
4623 : {
4624 1197171 : struct ldb_context *ldb = ldb_module_get_ctx(module);
4625 1197171 : const char *operation = NULL;
4626 1197171 : const struct ldb_message *msg = NULL;
4627 1197171 : struct ph_context *ac = NULL;
4628 1197171 : const char *passwordAttrs[] = {
4629 : DSDB_PASSWORD_ATTRIBUTES,
4630 : NULL
4631 : };
4632 1197171 : const char **a = NULL;
4633 1197171 : unsigned int attr_cnt = 0;
4634 1197171 : struct ldb_control *bypass = NULL;
4635 1197171 : struct ldb_control *uac_ctrl = NULL;
4636 1197171 : bool userPassword = dsdb_user_password_support(module, req, req);
4637 1197171 : bool update_password = false;
4638 1197171 : bool processing_needed = false;
4639 :
4640 1197171 : *_ac = NULL;
4641 :
4642 1197171 : ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_needed\n");
4643 :
4644 1197171 : switch (req->operation) {
4645 543158 : case LDB_ADD:
4646 543158 : operation = "add";
4647 543158 : msg = req->op.add.message;
4648 543158 : break;
4649 654013 : case LDB_MODIFY:
4650 654013 : operation = "modify";
4651 654013 : msg = req->op.mod.message;
4652 654013 : break;
4653 0 : default:
4654 0 : return ldb_next_request(module, req);
4655 : }
4656 :
4657 1197171 : if (ldb_dn_is_special(msg->dn)) { /* do not manipulate our control entries */
4658 1253 : return ldb_next_request(module, req);
4659 : }
4660 :
4661 1195918 : bypass = ldb_request_get_control(req,
4662 : DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID);
4663 1195918 : if (bypass != NULL) {
4664 : /* Mark the "bypass" control as uncritical (done) */
4665 23 : bypass->critical = false;
4666 23 : ldb_debug(ldb, LDB_DEBUG_TRACE,
4667 : "password_hash_needed(%s) (bypassing)\n",
4668 : operation);
4669 23 : return password_hash_bypass(module, req);
4670 : }
4671 :
4672 : /* nobody must touch password histories and 'supplementalCredentials' */
4673 1195895 : if (ldb_msg_find_element(msg, "ntPwdHistory")) {
4674 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
4675 : }
4676 1195895 : if (ldb_msg_find_element(msg, "lmPwdHistory")) {
4677 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
4678 : }
4679 1195895 : if (ldb_msg_find_element(msg, "supplementalCredentials")) {
4680 0 : return LDB_ERR_UNWILLING_TO_PERFORM;
4681 : }
4682 :
4683 : /*
4684 : * If no part of this touches the 'userPassword' OR 'clearTextPassword'
4685 : * OR 'unicodePwd' OR 'dBCSPwd' we don't need to make any changes.
4686 : * For password changes/set there should be a 'delete' or a 'modify'
4687 : * on these attributes.
4688 : */
4689 5979451 : for (a = passwordAttrs; *a != NULL; a++) {
4690 4783562 : if ((!userPassword) && (ldb_attr_cmp(*a, "userPassword") == 0)) {
4691 1181161 : continue;
4692 : }
4693 :
4694 3602401 : if (ldb_msg_find_element(msg, *a) != NULL) {
4695 : /* MS-ADTS 3.1.1.3.1.5.2 */
4696 24509 : if ((ldb_attr_cmp(*a, "userPassword") == 0) &&
4697 1972 : (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003)) {
4698 6 : return LDB_ERR_CONSTRAINT_VIOLATION;
4699 : }
4700 :
4701 22531 : ++attr_cnt;
4702 : }
4703 : }
4704 :
4705 1195889 : if (attr_cnt > 0) {
4706 22513 : update_password = true;
4707 22513 : processing_needed = true;
4708 : }
4709 :
4710 1195889 : if (ldb_msg_find_element(msg, "pwdLastSet")) {
4711 30492 : processing_needed = true;
4712 : }
4713 :
4714 1195889 : uac_ctrl = ldb_request_get_control(req,
4715 : DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID);
4716 1195889 : if (uac_ctrl != NULL) {
4717 46139 : struct dsdb_control_password_user_account_control *uac = NULL;
4718 46139 : uint32_t added_flags = 0;
4719 :
4720 46139 : uac = talloc_get_type_abort(uac_ctrl->data,
4721 : struct dsdb_control_password_user_account_control);
4722 :
4723 46139 : added_flags = uac->new_flags & ~uac->old_flags;
4724 :
4725 46139 : if (added_flags & UF_SMARTCARD_REQUIRED) {
4726 23 : processing_needed = true;
4727 : }
4728 : }
4729 :
4730 1195889 : if (!processing_needed) {
4731 1146879 : return ldb_next_request(module, req);
4732 : }
4733 :
4734 49010 : ac = ph_init_context(module, req, userPassword, update_password);
4735 49010 : if (!ac) {
4736 0 : DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
4737 0 : return ldb_operr(ldb);
4738 : }
4739 49010 : ph_apply_controls(ac);
4740 :
4741 : /*
4742 : * Make a copy in order to apply our modifications
4743 : * to the final update
4744 : */
4745 49010 : ac->update_msg = ldb_msg_copy_shallow(ac, msg);
4746 49010 : if (ac->update_msg == NULL) {
4747 0 : return ldb_oom(ldb);
4748 : }
4749 :
4750 49010 : dsdb_remove_password_related_attrs(ac->update_msg, ac->userPassword);
4751 :
4752 49010 : *_ac = ac;
4753 49010 : return LDB_SUCCESS;
4754 : }
4755 :
4756 543158 : static int password_hash_add(struct ldb_module *module, struct ldb_request *req)
4757 : {
4758 543158 : struct ldb_context *ldb = ldb_module_get_ctx(module);
4759 543158 : struct ph_context *ac = NULL;
4760 83687 : int ret;
4761 :
4762 543158 : ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_add\n");
4763 :
4764 543158 : ret = password_hash_needed(module, req, &ac);
4765 543158 : if (ret != LDB_SUCCESS) {
4766 44 : return ret;
4767 : }
4768 543114 : if (ac == NULL) {
4769 429365 : return ret;
4770 : }
4771 :
4772 : /* Make sure we are performing the password set action on a (for us)
4773 : * valid object. Those are instances of either "user" and/or
4774 : * "inetOrgPerson". Otherwise continue with the submodules. */
4775 30283 : if ((!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "user"))
4776 0 : && (!ldb_msg_check_string_attribute(req->op.add.message, "objectClass", "inetOrgPerson"))) {
4777 :
4778 0 : TALLOC_FREE(ac);
4779 :
4780 0 : if (ldb_msg_find_element(req->op.add.message, "clearTextPassword") != NULL) {
4781 0 : ldb_set_errstring(ldb,
4782 : "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
4783 0 : return LDB_ERR_NO_SUCH_ATTRIBUTE;
4784 : }
4785 :
4786 0 : return ldb_next_request(module, req);
4787 : }
4788 :
4789 : /* get user domain data */
4790 30283 : ret = build_domain_data_request(ac);
4791 30283 : if (ret != LDB_SUCCESS) {
4792 0 : return ret;
4793 : }
4794 :
4795 30283 : return ldb_next_request(module, ac->dom_req);
4796 : }
4797 :
4798 30283 : static int password_hash_add_do_add(struct ph_context *ac)
4799 : {
4800 30283 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
4801 221 : struct ldb_request *down_req;
4802 221 : struct setup_password_fields_io io;
4803 221 : int ret;
4804 :
4805 : /* Prepare the internal data structure containing the passwords */
4806 30283 : ret = setup_io(ac, ac->req->op.add.message, NULL, &io);
4807 30283 : if (ret != LDB_SUCCESS) {
4808 36 : return ret;
4809 : }
4810 :
4811 30247 : ret = setup_password_fields(&io);
4812 30247 : if (ret != LDB_SUCCESS) {
4813 8 : return ret;
4814 : }
4815 :
4816 30239 : ret = check_password_restrictions_and_log(&io);
4817 30239 : if (ret != LDB_SUCCESS) {
4818 1 : return ret;
4819 : }
4820 :
4821 30238 : ret = setup_smartcard_reset(&io);
4822 30238 : if (ret != LDB_SUCCESS) {
4823 0 : return ret;
4824 : }
4825 :
4826 30238 : ret = update_final_msg(&io);
4827 30238 : if (ret != LDB_SUCCESS) {
4828 0 : return ret;
4829 : }
4830 :
4831 30459 : ret = ldb_build_add_req(&down_req, ldb, ac,
4832 30238 : ac->update_msg,
4833 30017 : ac->req->controls,
4834 : ac, ph_op_callback,
4835 : ac->req);
4836 30238 : LDB_REQ_SET_LOCATION(down_req);
4837 30238 : if (ret != LDB_SUCCESS) {
4838 0 : return ret;
4839 : }
4840 :
4841 30238 : return ldb_next_request(ac->module, down_req);
4842 : }
4843 :
4844 654013 : static int password_hash_modify(struct ldb_module *module, struct ldb_request *req)
4845 : {
4846 654013 : struct ldb_context *ldb = ldb_module_get_ctx(module);
4847 654013 : struct ph_context *ac = NULL;
4848 654013 : const char *passwordAttrs[] = {DSDB_PASSWORD_ATTRIBUTES, NULL}, **l;
4849 27646 : unsigned int del_attr_cnt, add_attr_cnt, rep_attr_cnt;
4850 27646 : struct ldb_message_element *passwordAttr;
4851 27646 : struct ldb_message *msg;
4852 27646 : struct ldb_request *down_req;
4853 654013 : struct ldb_control *restore = NULL;
4854 27646 : int ret;
4855 654013 : unsigned int i = 0;
4856 :
4857 654013 : ldb_debug(ldb, LDB_DEBUG_TRACE, "password_hash_modify\n");
4858 :
4859 654013 : ret = password_hash_needed(module, req, &ac);
4860 654013 : if (ret != LDB_SUCCESS) {
4861 145 : return ret;
4862 : }
4863 653868 : if (ac == NULL) {
4864 607634 : return ret;
4865 : }
4866 :
4867 : /* use a new message structure so that we can modify it */
4868 18727 : msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
4869 18727 : if (msg == NULL) {
4870 0 : return ldb_oom(ldb);
4871 : }
4872 :
4873 : /* - check for single-valued password attributes
4874 : * (if not return "CONSTRAINT_VIOLATION")
4875 : * - check that for a password change operation one add and one delete
4876 : * operation exists
4877 : * (if not return "CONSTRAINT_VIOLATION" or "UNWILLING_TO_PERFORM")
4878 : * - check that a password change and a password set operation cannot
4879 : * be mixed
4880 : * (if not return "UNWILLING_TO_PERFORM")
4881 : * - remove all password attributes modifications from the first change
4882 : * operation (anything without the passwords) - we will make the real
4883 : * modification later */
4884 18588 : del_attr_cnt = 0;
4885 18588 : add_attr_cnt = 0;
4886 18588 : rep_attr_cnt = 0;
4887 92465 : for (l = passwordAttrs; *l != NULL; l++) {
4888 74044 : if ((!ac->userPassword) &&
4889 63844 : (ldb_attr_cmp(*l, "userPassword") == 0)) {
4890 15961 : continue;
4891 : }
4892 :
4893 78250 : while ((passwordAttr = ldb_msg_find_element(msg, *l)) != NULL) {
4894 20473 : unsigned int mtype = LDB_FLAG_MOD_TYPE(passwordAttr->flags);
4895 20473 : unsigned int nvalues = passwordAttr->num_values;
4896 :
4897 20473 : if (mtype == LDB_FLAG_MOD_DELETE) {
4898 2113 : ++del_attr_cnt;
4899 : }
4900 20473 : if (mtype == LDB_FLAG_MOD_ADD) {
4901 2061 : ++add_attr_cnt;
4902 : }
4903 20473 : if (mtype == LDB_FLAG_MOD_REPLACE) {
4904 16299 : ++rep_attr_cnt;
4905 : }
4906 20473 : if ((nvalues != 1) && (mtype == LDB_FLAG_MOD_ADD)) {
4907 288 : talloc_free(ac);
4908 288 : ldb_asprintf_errstring(ldb,
4909 : "'%s' attribute must have exactly one value on add operations!",
4910 : *l);
4911 288 : return LDB_ERR_CONSTRAINT_VIOLATION;
4912 : }
4913 20185 : if ((nvalues > 1) && (mtype == LDB_FLAG_MOD_DELETE)) {
4914 18 : talloc_free(ac);
4915 18 : ldb_asprintf_errstring(ldb,
4916 : "'%s' attribute must have zero or one value(s) on delete operations!",
4917 : *l);
4918 18 : return LDB_ERR_CONSTRAINT_VIOLATION;
4919 : }
4920 20167 : ldb_msg_remove_element(msg, passwordAttr);
4921 : }
4922 : }
4923 18421 : if ((del_attr_cnt == 0) && (add_attr_cnt > 0)) {
4924 9 : talloc_free(ac);
4925 9 : ldb_set_errstring(ldb,
4926 : "Only the add action for a password change specified!");
4927 9 : return LDB_ERR_UNWILLING_TO_PERFORM;
4928 : }
4929 18412 : if ((del_attr_cnt > 1) || (add_attr_cnt > 1)) {
4930 25 : talloc_free(ac);
4931 25 : ldb_set_errstring(ldb,
4932 : "Only one delete and one add action for a password change allowed!");
4933 25 : return LDB_ERR_UNWILLING_TO_PERFORM;
4934 : }
4935 18387 : if ((rep_attr_cnt > 0) && ((del_attr_cnt > 0) || (add_attr_cnt > 0))) {
4936 9 : talloc_free(ac);
4937 9 : ldb_set_errstring(ldb,
4938 : "Either a password change or a password set operation is allowed!");
4939 9 : return LDB_ERR_UNWILLING_TO_PERFORM;
4940 : }
4941 :
4942 18378 : restore = ldb_request_get_control(req,
4943 : DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
4944 18378 : if (restore == NULL) {
4945 : /*
4946 : * A tombstone reanimation generates a double update
4947 : * of pwdLastSet.
4948 : *
4949 : * So we only remove it without the
4950 : * DSDB_CONTROL_RESTORE_TOMBSTONE_OID control.
4951 : */
4952 18327 : ldb_msg_remove_attr(msg, "pwdLastSet");
4953 : }
4954 :
4955 :
4956 : /* if there was nothing else to be modified skip to next step */
4957 18378 : if (msg->num_elements == 0) {
4958 18305 : return password_hash_mod_search_self(ac);
4959 : }
4960 :
4961 : /*
4962 : * Now we apply all changes remaining in msg
4963 : * and remove them from our final update_msg
4964 : */
4965 :
4966 959 : for (i = 0; i < msg->num_elements; i++) {
4967 886 : ldb_msg_remove_attr(ac->update_msg,
4968 886 : msg->elements[i].name);
4969 : }
4970 :
4971 73 : ret = ldb_build_mod_req(&down_req, ldb, ac,
4972 : msg,
4973 : req->controls,
4974 : ac, ph_modify_callback,
4975 : req);
4976 73 : LDB_REQ_SET_LOCATION(down_req);
4977 73 : if (ret != LDB_SUCCESS) {
4978 0 : return ret;
4979 : }
4980 :
4981 73 : return ldb_next_request(module, down_req);
4982 : }
4983 :
4984 73 : static int ph_modify_callback(struct ldb_request *req, struct ldb_reply *ares)
4985 : {
4986 2 : struct ph_context *ac;
4987 :
4988 73 : ac = talloc_get_type(req->context, struct ph_context);
4989 :
4990 73 : if (!ares) {
4991 0 : return ldb_module_done(ac->req, NULL, NULL,
4992 : LDB_ERR_OPERATIONS_ERROR);
4993 : }
4994 :
4995 73 : if (ares->type == LDB_REPLY_REFERRAL) {
4996 0 : return ldb_module_send_referral(ac->req, ares->referral);
4997 : }
4998 :
4999 73 : if (ares->error != LDB_SUCCESS) {
5000 0 : return ldb_module_done(ac->req, ares->controls,
5001 : ares->response, ares->error);
5002 : }
5003 :
5004 73 : if (ares->type != LDB_REPLY_DONE) {
5005 0 : talloc_free(ares);
5006 0 : return ldb_module_done(ac->req, NULL, NULL,
5007 : LDB_ERR_OPERATIONS_ERROR);
5008 : }
5009 :
5010 73 : talloc_free(ares);
5011 :
5012 73 : return password_hash_mod_search_self(ac);
5013 : }
5014 :
5015 36756 : static int ph_mod_search_callback(struct ldb_request *req, struct ldb_reply *ares)
5016 : {
5017 278 : struct ldb_context *ldb;
5018 278 : struct ph_context *ac;
5019 36756 : int ret = LDB_SUCCESS;
5020 :
5021 36756 : ac = talloc_get_type(req->context, struct ph_context);
5022 36756 : ldb = ldb_module_get_ctx(ac->module);
5023 :
5024 36756 : if (!ares) {
5025 0 : ret = LDB_ERR_OPERATIONS_ERROR;
5026 0 : goto done;
5027 : }
5028 36756 : if (ares->error != LDB_SUCCESS) {
5029 0 : return ldb_module_done(ac->req, ares->controls,
5030 : ares->response, ares->error);
5031 : }
5032 :
5033 : /* we are interested only in the single reply (base search) */
5034 36756 : switch (ares->type) {
5035 18378 : case LDB_REPLY_ENTRY:
5036 : /* Make sure we are performing the password change action on a
5037 : * (for us) valid object. Those are instances of either "user"
5038 : * and/or "inetOrgPerson". Otherwise continue with the
5039 : * submodules. */
5040 18378 : if ((!ldb_msg_check_string_attribute(ares->message, "objectClass", "user"))
5041 0 : && (!ldb_msg_check_string_attribute(ares->message, "objectClass", "inetOrgPerson"))) {
5042 0 : talloc_free(ares);
5043 :
5044 0 : if (ldb_msg_find_element(ac->req->op.mod.message, "clearTextPassword") != NULL) {
5045 0 : ldb_set_errstring(ldb,
5046 : "'clearTextPassword' is only allowed on objects of class 'user' and/or 'inetOrgPerson'!");
5047 0 : ret = LDB_ERR_NO_SUCH_ATTRIBUTE;
5048 0 : goto done;
5049 : }
5050 :
5051 0 : ret = ldb_next_request(ac->module, ac->req);
5052 0 : goto done;
5053 : }
5054 :
5055 18378 : if (ac->search_res != NULL) {
5056 0 : talloc_free(ares);
5057 :
5058 0 : ldb_set_errstring(ldb, "Too many results");
5059 0 : ret = LDB_ERR_OPERATIONS_ERROR;
5060 0 : goto done;
5061 : }
5062 :
5063 18378 : ac->search_res = talloc_steal(ac, ares);
5064 18378 : ret = LDB_SUCCESS;
5065 18378 : break;
5066 :
5067 0 : case LDB_REPLY_REFERRAL:
5068 : /* ignore anything else for now */
5069 0 : talloc_free(ares);
5070 0 : ret = LDB_SUCCESS;
5071 0 : break;
5072 :
5073 18378 : case LDB_REPLY_DONE:
5074 18378 : talloc_free(ares);
5075 :
5076 : /* get user domain data */
5077 18378 : ret = build_domain_data_request(ac);
5078 18378 : if (ret != LDB_SUCCESS) {
5079 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
5080 : }
5081 :
5082 18378 : ret = ldb_next_request(ac->module, ac->dom_req);
5083 18378 : break;
5084 : }
5085 :
5086 36617 : done:
5087 36756 : if (ret != LDB_SUCCESS) {
5088 0 : return ldb_module_done(ac->req, NULL, NULL, ret);
5089 : }
5090 :
5091 36478 : return LDB_SUCCESS;
5092 : }
5093 :
5094 18378 : static int password_hash_mod_search_self(struct ph_context *ac)
5095 : {
5096 139 : struct ldb_context *ldb;
5097 139 : static const char * const attrs[] = { "objectClass",
5098 : "userAccountControl",
5099 : "msDS-ResultantPSO",
5100 : "msDS-User-Account-Control-Computed",
5101 : "pwdLastSet",
5102 : "sAMAccountName",
5103 : "objectSid",
5104 : "userPrincipalName",
5105 : "displayName",
5106 : "supplementalCredentials",
5107 : "lmPwdHistory",
5108 : "ntPwdHistory",
5109 : "dBCSPwd",
5110 : "unicodePwd",
5111 : "badPasswordTime",
5112 : "badPwdCount",
5113 : "lockoutTime",
5114 : "msDS-KeyVersionNumber",
5115 : "msDS-SecondaryKrbTgtNumber",
5116 : NULL };
5117 139 : struct ldb_request *search_req;
5118 139 : int ret;
5119 :
5120 18378 : ldb = ldb_module_get_ctx(ac->module);
5121 :
5122 18517 : ret = ldb_build_search_req(&search_req, ldb, ac,
5123 18378 : ac->req->op.mod.message->dn,
5124 : LDB_SCOPE_BASE,
5125 : "(objectclass=*)",
5126 : attrs,
5127 : NULL,
5128 : ac, ph_mod_search_callback,
5129 : ac->req);
5130 18378 : LDB_REQ_SET_LOCATION(search_req);
5131 18378 : if (ret != LDB_SUCCESS) {
5132 0 : return ret;
5133 : }
5134 :
5135 18378 : return ldb_next_request(ac->module, search_req);
5136 : }
5137 :
5138 18378 : static int password_hash_mod_do_mod(struct ph_context *ac)
5139 : {
5140 18378 : struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
5141 139 : struct ldb_request *mod_req;
5142 139 : struct setup_password_fields_io io;
5143 139 : int ret;
5144 :
5145 : /* Prepare the internal data structure containing the passwords */
5146 18517 : ret = setup_io(ac, ac->req->op.mod.message,
5147 18378 : ac->search_res->message, &io);
5148 18378 : if (ret != LDB_SUCCESS) {
5149 221 : return ret;
5150 : }
5151 :
5152 18157 : ret = setup_password_fields(&io);
5153 18157 : if (ret != LDB_SUCCESS) {
5154 9 : return ret;
5155 : }
5156 :
5157 18148 : ret = check_password_restrictions_and_log(&io);
5158 18148 : if (ret != LDB_SUCCESS) {
5159 962 : return ret;
5160 : }
5161 :
5162 17186 : ret = setup_smartcard_reset(&io);
5163 17186 : if (ret != LDB_SUCCESS) {
5164 0 : return ret;
5165 : }
5166 :
5167 17186 : ret = update_final_msg(&io);
5168 17186 : if (ret != LDB_SUCCESS) {
5169 0 : return ret;
5170 : }
5171 :
5172 17325 : ret = ldb_build_mod_req(&mod_req, ldb, ac,
5173 17186 : ac->update_msg,
5174 17047 : ac->req->controls,
5175 : ac, ph_op_callback,
5176 : ac->req);
5177 17186 : LDB_REQ_SET_LOCATION(mod_req);
5178 17186 : if (ret != LDB_SUCCESS) {
5179 0 : return ret;
5180 : }
5181 :
5182 17186 : return ldb_next_request(ac->module, mod_req);
5183 : }
5184 :
5185 : static const struct ldb_module_ops ldb_password_hash_module_ops = {
5186 : .name = "password_hash",
5187 : .add = password_hash_add,
5188 : .modify = password_hash_modify
5189 : };
5190 :
5191 6286 : int ldb_password_hash_module_init(const char *version)
5192 : {
5193 : #ifdef ENABLE_GPGME
5194 6286 : const char *gversion = NULL;
5195 : #endif /* ENABLE_GPGME */
5196 :
5197 6286 : LDB_MODULE_CHECK_VERSION(version);
5198 :
5199 : #ifdef ENABLE_GPGME
5200 : /*
5201 : * Note: this sets a SIGPIPE handler
5202 : * if none is active already. See:
5203 : * https://www.gnupg.org/documentation/manuals/gpgme/Signal-Handling.html#Signal-Handling
5204 : */
5205 6286 : gversion = gpgme_check_version(MINIMUM_GPGME_VERSION);
5206 6286 : if (gversion == NULL) {
5207 0 : fprintf(stderr, "%s() in %s version[%s]: "
5208 : "gpgme_check_version(%s) not available, "
5209 : "gpgme_check_version(NULL) => '%s'\n",
5210 : __func__, __FILE__, version,
5211 : MINIMUM_GPGME_VERSION, gpgme_check_version(NULL));
5212 0 : return LDB_ERR_UNAVAILABLE;
5213 : }
5214 : #endif /* ENABLE_GPGME */
5215 :
5216 6286 : return ldb_register_module(&ldb_password_hash_module_ops);
5217 : }
|