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 master 2f515e9b Lines: 1597 2244 71.2 %
Date: 2024-04-21 15:09:00 Functions: 38 38 100.0 %

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

Generated by: LCOV version 1.14