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

Generated by: LCOV version 1.14