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