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