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 abartlet/fix-coverage dd10fb34 Lines: 1427 1991 71.7 %
Date: 2021-09-23 10:06:22 Functions: 43 44 97.7 %

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

Generated by: LCOV version 1.13