LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - password_hash.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 1445 2025 71.4 %
Date: 2024-06-13 04:01:37 Functions: 38 38 100.0 %

          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             :                 &current);
    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             :                                            &quoted_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             : }

Generated by: LCOV version 1.13