LCOV - code coverage report
Current view: top level - source4/dsdb/common - util.c (source / functions) Hit Total Coverage
Test: coverage report for master 98b443d9 Lines: 2240 3259 68.7 %
Date: 2024-05-31 13:13:24 Functions: 172 183 94.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Samba utility functions
       4             : 
       5             :    Copyright (C) Andrew Tridgell 2004
       6             :    Copyright (C) Volker Lendecke 2004
       7             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
       8             :    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
       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             : #include "includes.h"
      25             : #include "ldb.h"
      26             : #include "ldb_module.h"
      27             : #include "ldb_errors.h"
      28             : #include "../lib/util/util_ldb.h"
      29             : #include "lib/crypto/gmsa.h"
      30             : #include "dsdb/samdb/samdb.h"
      31             : #include "librpc/gen_ndr/ndr_security.h"
      32             : #include "librpc/gen_ndr/ndr_misc.h"
      33             : #include "../libds/common/flags.h"
      34             : #include "dsdb/common/proto.h"
      35             : #include "libcli/ldap/ldap_ndr.h"
      36             : #include "param/param.h"
      37             : #include "librpc/gen_ndr/ndr_drsblobs.h"
      38             : #include "dsdb/common/util.h"
      39             : #include "dsdb/gmsa/gkdi.h"
      40             : #include "dsdb/gmsa/util.h"
      41             : #include "lib/socket/socket.h"
      42             : #include "librpc/gen_ndr/irpc.h"
      43             : #include "libds/common/flag_mapping.h"
      44             : #include "lib/util/access.h"
      45             : #include "lib/util/data_blob.h"
      46             : #include "lib/util/debug.h"
      47             : #include "lib/util/fault.h"
      48             : #include "lib/util/sys_rw_data.h"
      49             : #include "libcli/util/ntstatus.h"
      50             : #include "lib/util/smb_strtox.h"
      51             : #include "auth/auth.h"
      52             : 
      53             : #undef strncasecmp
      54             : #undef strcasecmp
      55             : 
      56             : /*
      57             :  * This is included to allow us to handle DSDB_FLAG_REPLICATED_UPDATE in
      58             :  * dsdb_request_add_controls()
      59             :  */
      60             : #include "dsdb/samdb/ldb_modules/util.h"
      61             : 
      62             : /* default is 30 minutes: -1e7 * 30 * 60 */
      63             : #define DEFAULT_OBSERVATION_WINDOW              (-18000000000)
      64             : 
      65             : /*
      66             :   search the sam for the specified attributes in a specific domain, filter on
      67             :   objectSid being in domain_sid.
      68             : */
      69         335 : int samdb_search_domain(struct ldb_context *sam_ldb,
      70             :                         TALLOC_CTX *mem_ctx,
      71             :                         struct ldb_dn *basedn,
      72             :                         struct ldb_message ***res,
      73             :                         const char * const *attrs,
      74             :                         const struct dom_sid *domain_sid,
      75             :                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
      76             : {
      77           0 :         va_list ap;
      78           0 :         int i, count;
      79             : 
      80         335 :         va_start(ap, format);
      81         335 :         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
      82             :                                res, attrs, format, ap);
      83         335 :         va_end(ap);
      84             : 
      85         335 :         i=0;
      86             : 
      87        3289 :         while (i<count) {
      88           0 :                 struct dom_sid *entry_sid;
      89             : 
      90        2954 :                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
      91             : 
      92        2954 :                 if ((entry_sid == NULL) ||
      93        2954 :                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
      94             :                         /* Delete that entry from the result set */
      95         858 :                         (*res)[i] = (*res)[count-1];
      96         858 :                         count -= 1;
      97         858 :                         talloc_free(entry_sid);
      98         858 :                         continue;
      99             :                 }
     100        2096 :                 talloc_free(entry_sid);
     101        2096 :                 i += 1;
     102             :         }
     103             : 
     104         335 :         return count;
     105             : }
     106             : 
     107             : /*
     108             :   search the sam for a single string attribute in exactly 1 record
     109             : */
     110        2360 : const char *samdb_search_string_v(struct ldb_context *sam_ldb,
     111             :                                   TALLOC_CTX *mem_ctx,
     112             :                                   struct ldb_dn *basedn,
     113             :                                   const char *attr_name,
     114             :                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
     115             : {
     116         117 :         int count;
     117        2360 :         const char *attrs[2] = { NULL, NULL };
     118        2360 :         struct ldb_message **res = NULL;
     119             : 
     120        2360 :         attrs[0] = attr_name;
     121             : 
     122        2360 :         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
     123        2360 :         if (count > 1) {
     124           0 :                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
     125             :                          attr_name, format, count));
     126             :         }
     127        2360 :         if (count != 1) {
     128        2137 :                 talloc_free(res);
     129        2137 :                 return NULL;
     130             :         }
     131             : 
     132         223 :         return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
     133             : }
     134             : 
     135             : /*
     136             :   search the sam for a single string attribute in exactly 1 record
     137             : */
     138        2360 : const char *samdb_search_string(struct ldb_context *sam_ldb,
     139             :                                 TALLOC_CTX *mem_ctx,
     140             :                                 struct ldb_dn *basedn,
     141             :                                 const char *attr_name,
     142             :                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
     143             : {
     144         117 :         va_list ap;
     145         117 :         const char *str;
     146             : 
     147        2360 :         va_start(ap, format);
     148        2360 :         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
     149        2360 :         va_end(ap);
     150             : 
     151        2360 :         return str;
     152             : }
     153             : 
     154        4000 : struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
     155             :                                TALLOC_CTX *mem_ctx,
     156             :                                struct ldb_dn *basedn,
     157             :                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
     158             : {
     159         188 :         va_list ap;
     160         188 :         struct ldb_dn *ret;
     161        4000 :         struct ldb_message **res = NULL;
     162         188 :         int count;
     163             : 
     164        4000 :         va_start(ap, format);
     165        4000 :         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
     166        4000 :         va_end(ap);
     167             : 
     168        4000 :         if (count != 1) return NULL;
     169             : 
     170        4000 :         ret = talloc_steal(mem_ctx, res[0]->dn);
     171        4000 :         talloc_free(res);
     172             : 
     173        4000 :         return ret;
     174             : }
     175             : 
     176             : /*
     177             :   search the sam for a dom_sid attribute in exactly 1 record
     178             : */
     179         981 : struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
     180             :                                      TALLOC_CTX *mem_ctx,
     181             :                                      struct ldb_dn *basedn,
     182             :                                      const char *attr_name,
     183             :                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
     184             : {
     185           0 :         va_list ap;
     186           0 :         int count;
     187           0 :         struct ldb_message **res;
     188         981 :         const char *attrs[2] = { NULL, NULL };
     189           0 :         struct dom_sid *sid;
     190             : 
     191         981 :         attrs[0] = attr_name;
     192             : 
     193         981 :         va_start(ap, format);
     194         981 :         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
     195         981 :         va_end(ap);
     196         981 :         if (count > 1) {
     197           0 :                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n",
     198             :                          attr_name, format, count));
     199             :         }
     200         981 :         if (count != 1) {
     201           0 :                 talloc_free(res);
     202           0 :                 return NULL;
     203             :         }
     204         981 :         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
     205         981 :         talloc_free(res);
     206         981 :         return sid;
     207             : }
     208             : 
     209             : /*
     210             :   search the sam for a single integer attribute in exactly 1 record
     211             : */
     212        2529 : unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
     213             :                          TALLOC_CTX *mem_ctx,
     214             :                          unsigned int default_value,
     215             :                          struct ldb_dn *basedn,
     216             :                          const char *attr_name,
     217             :                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
     218             : {
     219         146 :         va_list ap;
     220         146 :         int count;
     221         146 :         struct ldb_message **res;
     222        2529 :         const char *attrs[2] = { NULL, NULL };
     223             : 
     224        2529 :         attrs[0] = attr_name;
     225             : 
     226        2529 :         va_start(ap, format);
     227        2529 :         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
     228        2529 :         va_end(ap);
     229             : 
     230        2529 :         if (count != 1) {
     231           0 :                 return default_value;
     232             :         }
     233             : 
     234        2529 :         return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
     235             : }
     236             : 
     237             : /*
     238             :   search the sam for a single signed 64 bit integer attribute in exactly 1 record
     239             : */
     240      788160 : int64_t samdb_search_int64(struct ldb_context *sam_ldb,
     241             :                            TALLOC_CTX *mem_ctx,
     242             :                            int64_t default_value,
     243             :                            struct ldb_dn *basedn,
     244             :                            const char *attr_name,
     245             :                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
     246             : {
     247       27882 :         va_list ap;
     248       27882 :         int count;
     249       27882 :         struct ldb_message **res;
     250      788160 :         const char *attrs[2] = { NULL, NULL };
     251             : 
     252      788160 :         attrs[0] = attr_name;
     253             : 
     254      788160 :         va_start(ap, format);
     255      788160 :         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
     256      788160 :         va_end(ap);
     257             : 
     258      788160 :         if (count != 1) {
     259           0 :                 return default_value;
     260             :         }
     261             : 
     262      788160 :         return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
     263             : }
     264             : 
     265             : /*
     266             :   search the sam for multiple records each giving a single string attribute
     267             :   return the number of matches, or -1 on error
     268             : */
     269           0 : int samdb_search_string_multiple(struct ldb_context *sam_ldb,
     270             :                                  TALLOC_CTX *mem_ctx,
     271             :                                  struct ldb_dn *basedn,
     272             :                                  const char ***strs,
     273             :                                  const char *attr_name,
     274             :                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
     275             : {
     276           0 :         va_list ap;
     277           0 :         int count, i;
     278           0 :         const char *attrs[2] = { NULL, NULL };
     279           0 :         struct ldb_message **res = NULL;
     280             : 
     281           0 :         attrs[0] = attr_name;
     282             : 
     283           0 :         va_start(ap, format);
     284           0 :         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
     285           0 :         va_end(ap);
     286             : 
     287           0 :         if (count <= 0) {
     288           0 :                 return count;
     289             :         }
     290             : 
     291             :         /* make sure its single valued */
     292           0 :         for (i=0;i<count;i++) {
     293           0 :                 if (res[i]->num_elements != 1) {
     294           0 :                         DEBUG(1,("samdb: search for %s %s not single valued\n",
     295             :                                  attr_name, format));
     296           0 :                         talloc_free(res);
     297           0 :                         return -1;
     298             :                 }
     299             :         }
     300             : 
     301           0 :         *strs = talloc_array(mem_ctx, const char *, count+1);
     302           0 :         if (! *strs) {
     303           0 :                 talloc_free(res);
     304           0 :                 return -1;
     305             :         }
     306             : 
     307           0 :         for (i=0;i<count;i++) {
     308           0 :                 (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
     309             :         }
     310           0 :         (*strs)[count] = NULL;
     311             : 
     312           0 :         return count;
     313             : }
     314             : 
     315      336674 : struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
     316             :                                const char *attr, struct ldb_dn *default_value)
     317             : {
     318      336674 :         struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
     319      336674 :         if (!ret_dn) {
     320       48085 :                 return default_value;
     321             :         }
     322      278743 :         return ret_dn;
     323             : }
     324             : 
     325             : /*
     326             :   pull a rid from a objectSid in a result set.
     327             : */
     328      789926 : uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
     329             :                                    const char *attr, uint32_t default_value)
     330             : {
     331       28721 :         struct dom_sid *sid;
     332       28721 :         uint32_t rid;
     333             : 
     334      789926 :         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
     335      789926 :         if (sid == NULL) {
     336           0 :                 return default_value;
     337             :         }
     338      789926 :         rid = sid->sub_auths[sid->num_auths-1];
     339      789926 :         talloc_free(sid);
     340      789926 :         return rid;
     341             : }
     342             : 
     343             : /*
     344             :   pull a dom_sid structure from a objectSid in a result set.
     345             : */
     346     6086943 : struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
     347             :                                      const char *attr)
     348             : {
     349      255920 :         ssize_t ret;
     350      255920 :         const struct ldb_val *v;
     351      255920 :         struct dom_sid *sid;
     352     6086943 :         v = ldb_msg_find_ldb_val(msg, attr);
     353     6086943 :         if (v == NULL) {
     354     4056036 :                 return NULL;
     355             :         }
     356     1832490 :         sid = talloc(mem_ctx, struct dom_sid);
     357     1832490 :         if (sid == NULL) {
     358           0 :                 return NULL;
     359             :         }
     360     1832490 :         ret = sid_parse(v->data, v->length, sid);
     361     1832490 :         if (ret == -1) {
     362           0 :                 talloc_free(sid);
     363           0 :                 return NULL;
     364             :         }
     365     1774987 :         return sid;
     366             : }
     367             : 
     368             : 
     369             : /**
     370             :  * Makes an auth_SidAttr structure from a objectSid in a result set and a
     371             :  * supplied attribute value.
     372             :  *
     373             :  * @param [in] mem_ctx  Talloc memory context on which to allocate the auth_SidAttr.
     374             :  * @param [in] msg      The message from which to take the objectSid.
     375             :  * @param [in] attr     The attribute name, usually "objectSid".
     376             :  * @param [in] attrs    SE_GROUP_* flags to go with the SID.
     377             :  * @returns A pointer to the auth_SidAttr structure, or NULL on failure.
     378             :  */
     379        1313 : struct auth_SidAttr *samdb_result_dom_sid_attrs(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
     380             :                                                 const char *attr, uint32_t attrs)
     381             : {
     382           0 :         ssize_t ret;
     383           0 :         const struct ldb_val *v;
     384           0 :         struct auth_SidAttr *sid;
     385        1313 :         v = ldb_msg_find_ldb_val(msg, attr);
     386        1313 :         if (v == NULL) {
     387           0 :                 return NULL;
     388             :         }
     389        1313 :         sid = talloc(mem_ctx, struct auth_SidAttr);
     390        1313 :         if (sid == NULL) {
     391           0 :                 return NULL;
     392             :         }
     393        1313 :         ret = sid_parse(v->data, v->length, &sid->sid);
     394        1313 :         if (ret == -1) {
     395           0 :                 talloc_free(sid);
     396           0 :                 return NULL;
     397             :         }
     398        1313 :         sid->attrs = attrs;
     399        1313 :         return sid;
     400             : }
     401             : 
     402             : /*
     403             :   pull a dom_sid structure from a objectSid in a result set.
     404             : */
     405     4168243 : int samdb_result_dom_sid_buf(const struct ldb_message *msg,
     406             :                              const char *attr,
     407             :                              struct dom_sid *sid)
     408             : {
     409       15428 :         ssize_t ret;
     410     4168243 :         const struct ldb_val *v = NULL;
     411     4168243 :         v = ldb_msg_find_ldb_val(msg, attr);
     412     4168243 :         if (v == NULL) {
     413      610297 :                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
     414             :         }
     415     3557944 :         ret = sid_parse(v->data, v->length, sid);
     416     3557944 :         if (ret == -1) {
     417           0 :                 return LDB_ERR_OPERATIONS_ERROR;
     418             :         }
     419     3542518 :         return LDB_SUCCESS;
     420             : }
     421             : 
     422             : /*
     423             :   pull a guid structure from a objectGUID in a result set.
     424             : */
     425   137942447 : struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
     426             : {
     427     1751126 :         const struct ldb_val *v;
     428     1751126 :         struct GUID guid;
     429     1751126 :         NTSTATUS status;
     430             : 
     431   137942447 :         v = ldb_msg_find_ldb_val(msg, attr);
     432   137942447 :         if (!v) return GUID_zero();
     433             : 
     434   103237647 :         status = GUID_from_ndr_blob(v, &guid);
     435   103237647 :         if (!NT_STATUS_IS_OK(status)) {
     436           0 :                 return GUID_zero();
     437             :         }
     438             : 
     439   103237647 :         return guid;
     440             : }
     441             : 
     442             : /*
     443             :   pull a sid prefix from a objectSid in a result set.
     444             :   this is used to find the domain sid for a user
     445             : */
     446           0 : struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
     447             :                                         const char *attr)
     448             : {
     449           0 :         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
     450           0 :         if (!sid || sid->num_auths < 1) return NULL;
     451           0 :         sid->num_auths--;
     452           0 :         return sid;
     453             : }
     454             : 
     455             : /*
     456             :   pull a NTTIME in a result set.
     457             : */
     458      463178 : NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
     459             :                            NTTIME default_value)
     460             : {
     461      463178 :         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
     462             : }
     463             : 
     464             : /*
     465             :  * Windows stores 0 for lastLogoff.
     466             :  * But when a MS DC return the lastLogoff (as Logoff Time)
     467             :  * it returns INT64_MAX, not returning this value in this case
     468             :  * cause windows 2008 and newer version to fail for SMB requests
     469             :  */
     470       79225 : NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
     471             : {
     472       79225 :         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
     473             : 
     474       79225 :         if (ret == 0)
     475       79224 :                 ret = INT64_MAX;
     476             : 
     477       79225 :         return ret;
     478             : }
     479             : 
     480             : /*
     481             :  * Windows uses both 0 and 9223372036854775807 (INT64_MAX) to
     482             :  * indicate an account doesn't expire.
     483             :  *
     484             :  * When Windows initially creates an account, it sets
     485             :  * accountExpires = 9223372036854775807 (INT64_MAX).  However,
     486             :  * when changing from an account having a specific expiration date to
     487             :  * that account never expiring, it sets accountExpires = 0.
     488             :  *
     489             :  * Consolidate that logic here to allow clearer logic for account expiry in
     490             :  * the rest of the code.
     491             :  */
     492      253168 : NTTIME samdb_result_account_expires(const struct ldb_message *msg)
     493             : {
     494      253168 :         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
     495             :                                                  0);
     496             : 
     497      253168 :         if (ret == 0)
     498          11 :                 ret = INT64_MAX;
     499             : 
     500      253168 :         return ret;
     501             : }
     502             : 
     503             : /*
     504             :   construct the allow_password_change field from the PwdLastSet attribute and the
     505             :   domain password settings
     506             : */
     507       83692 : NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb,
     508             :                                           TALLOC_CTX *mem_ctx,
     509             :                                           struct ldb_dn *domain_dn,
     510             :                                           const struct ldb_message *msg,
     511             :                                           const char *attr)
     512             : {
     513       83692 :         uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
     514        3228 :         int64_t minPwdAge;
     515             : 
     516       83692 :         if (attr_time == 0) {
     517        1763 :                 return 0;
     518             :         }
     519             : 
     520       81929 :         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
     521             : 
     522             :         /* yes, this is a -= not a += as minPwdAge is stored as the negative
     523             :            of the number of 100-nano-seconds */
     524       81929 :         attr_time -= minPwdAge;
     525             : 
     526       81929 :         return attr_time;
     527             : }
     528             : 
     529             : /*
     530             :   pull a samr_Password structure from a result set.
     531             : */
     532      325036 : struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, const char *attr)
     533             : {
     534      325036 :         struct samr_Password *hash = NULL;
     535      325036 :         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
     536      325036 :         if (val && (val->length >= sizeof(hash->hash))) {
     537      301328 :                 hash = talloc(mem_ctx, struct samr_Password);
     538      301328 :                 if (hash == NULL) {
     539           0 :                         return NULL;
     540             :                 }
     541      301328 :                 talloc_keep_secret(hash);
     542      301328 :                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
     543             :         }
     544      314657 :         return hash;
     545             : }
     546             : 
     547             : /*
     548             :   pull an array of samr_Password structures from a result set.
     549             : */
     550      394754 : unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
     551             :                            const char *attr, struct samr_Password **hashes)
     552             : {
     553       12252 :         unsigned int count, i;
     554      394754 :         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
     555             : 
     556      394754 :         *hashes = NULL;
     557      394754 :         if (!val) {
     558      247780 :                 return 0;
     559             :         }
     560      139885 :         if (val->length % 16 != 0) {
     561             :                 /*
     562             :                  * The length is wrong. Don’t try to read beyond the end of the
     563             :                  * buffer.
     564             :                  */
     565           0 :                 return 0;
     566             :         }
     567      139885 :         count = val->length / 16;
     568      139885 :         if (count == 0) {
     569           0 :                 return 0;
     570             :         }
     571             : 
     572      139885 :         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
     573      139885 :         if (! *hashes) {
     574           0 :                 return 0;
     575             :         }
     576      139885 :         talloc_keep_secret(*hashes);
     577             : 
     578      333493 :         for (i=0;i<count;i++) {
     579      188445 :                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
     580             :         }
     581             : 
     582      134722 :         return count;
     583             : }
     584             : 
     585        3766 : NTSTATUS samdb_result_passwords_from_history(TALLOC_CTX *mem_ctx,
     586             :                                              struct loadparm_context *lp_ctx,
     587             :                                              const struct ldb_message *msg,
     588             :                                              unsigned int idx,
     589             :                                              const struct samr_Password **lm_pwd,
     590             :                                              const struct samr_Password **nt_pwd)
     591             : {
     592           1 :         struct samr_Password *lmPwdHash, *ntPwdHash;
     593             : 
     594        3766 :         if (nt_pwd) {
     595           1 :                 unsigned int num_nt;
     596        3766 :                 num_nt = samdb_result_hashes(mem_ctx, msg, "ntPwdHistory", &ntPwdHash);
     597        3766 :                 if (num_nt <= idx) {
     598        2471 :                         *nt_pwd = NULL;
     599             :                 } else {
     600        1295 :                         *nt_pwd = &ntPwdHash[idx];
     601             :                 }
     602             :         }
     603        3766 :         if (lm_pwd) {
     604             :                 /* Ensure that if we have turned off LM
     605             :                  * authentication, that we never use the LM hash, even
     606             :                  * if we store it */
     607           0 :                 if (lpcfg_lanman_auth(lp_ctx)) {
     608           0 :                         unsigned int num_lm;
     609           0 :                         num_lm = samdb_result_hashes(mem_ctx, msg, "lmPwdHistory", &lmPwdHash);
     610           0 :                         if (num_lm <= idx) {
     611           0 :                                 *lm_pwd = NULL;
     612             :                         } else {
     613           0 :                                 *lm_pwd = &lmPwdHash[idx];
     614             :                         }
     615             :                 } else {
     616           0 :                         *lm_pwd = NULL;
     617             :                 }
     618             :         }
     619        3766 :         return NT_STATUS_OK;
     620             : }
     621             : 
     622       47886 : NTSTATUS samdb_result_passwords_no_lockout(TALLOC_CTX *mem_ctx,
     623             :                                            struct loadparm_context *lp_ctx,
     624             :                                            const struct ldb_message *msg,
     625             :                                            struct samr_Password **nt_pwd)
     626             : {
     627        1733 :         struct samr_Password *ntPwdHash;
     628             : 
     629       47886 :         if (nt_pwd) {
     630        1733 :                 unsigned int num_nt;
     631       47886 :                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
     632       47886 :                 if (num_nt == 0) {
     633       15413 :                         *nt_pwd = NULL;
     634       32473 :                 } else if (num_nt > 1) {
     635           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
     636             :                 } else {
     637       32473 :                         *nt_pwd = &ntPwdHash[0];
     638             :                 }
     639             :         }
     640       47886 :         return NT_STATUS_OK;
     641             : }
     642             : 
     643       30462 : NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx,
     644             :                                 struct loadparm_context *lp_ctx,
     645             :                                 const struct ldb_message *msg,
     646             :                                 struct samr_Password **nt_pwd)
     647             : {
     648        1442 :         uint16_t acct_flags;
     649             : 
     650       30462 :         acct_flags = samdb_result_acct_flags(msg,
     651             :                                              "msDS-User-Account-Control-Computed");
     652             :         /* Quit if the account was locked out. */
     653       30462 :         if (acct_flags & ACB_AUTOLOCK) {
     654         191 :                 DEBUG(3,("samdb_result_passwords: Account for user %s was locked out.\n",
     655             :                          ldb_dn_get_linearized(msg->dn)));
     656         191 :                 return NT_STATUS_ACCOUNT_LOCKED_OUT;
     657             :         }
     658             : 
     659       30271 :         return samdb_result_passwords_no_lockout(mem_ctx, lp_ctx, msg,
     660             :                                                  nt_pwd);
     661             : }
     662             : 
     663             : /*
     664             :   pull a samr_LogonHours structure from a result set.
     665             : */
     666        6373 : struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
     667             : {
     668        6373 :         struct samr_LogonHours hours = {};
     669        6373 :         size_t units_per_week = 168;
     670        6373 :         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
     671             : 
     672        6373 :         if (val) {
     673         279 :                 units_per_week = val->length * 8;
     674             :         }
     675             : 
     676        6373 :         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
     677        6373 :         if (!hours.bits) {
     678           0 :                 return hours;
     679             :         }
     680        6373 :         hours.units_per_week = units_per_week;
     681        6373 :         memset(hours.bits, 0xFF, units_per_week/8);
     682        6373 :         if (val) {
     683         279 :                 memcpy(hours.bits, val->data, val->length);
     684             :         }
     685             : 
     686        6373 :         return hours;
     687             : }
     688             : 
     689             : /*
     690             :   pull a set of account_flags from a result set.
     691             : 
     692             :   Naturally, this requires that userAccountControl and
     693             :   (if not null) the attributes 'attr' be already
     694             :   included in msg
     695             : */
     696      268143 : uint32_t samdb_result_acct_flags(const struct ldb_message *msg, const char *attr)
     697             : {
     698      268143 :         uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
     699      268143 :         uint32_t attr_flags = 0;
     700      268143 :         uint32_t acct_flags = ds_uf2acb(userAccountControl);
     701      268143 :         if (attr) {
     702      236680 :                 attr_flags = ldb_msg_find_attr_as_uint(msg, attr, UF_ACCOUNTDISABLE);
     703      236680 :                 if (attr_flags == UF_ACCOUNTDISABLE) {
     704           0 :                         DEBUG(0, ("Attribute %s not found, disabling account %s!\n", attr,
     705             :                                   ldb_dn_get_linearized(msg->dn)));
     706             :                 }
     707      236680 :                 acct_flags |= ds_uf2acb(attr_flags);
     708             :         }
     709             : 
     710      268143 :         return acct_flags;
     711             : }
     712             : 
     713        3145 : NTSTATUS samdb_result_parameters(TALLOC_CTX *mem_ctx,
     714             :                                  struct ldb_message *msg,
     715             :                                  const char *attr,
     716             :                                  struct lsa_BinaryString *s)
     717             : {
     718           0 :         int i;
     719        3145 :         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
     720             : 
     721        3145 :         ZERO_STRUCTP(s);
     722             : 
     723        3145 :         if (!val) {
     724        2542 :                 return NT_STATUS_OK;
     725             :         }
     726             : 
     727         603 :         if ((val->length % 2) != 0) {
     728             :                 /*
     729             :                  * If the on-disk data is not even in length, we know
     730             :                  * it is corrupt, and can not be safely pushed.  We
     731             :                  * would either truncate, send an uninitialised
     732             :                  * byte or send a forced zero byte
     733             :                  */
     734           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
     735             :         }
     736             : 
     737         603 :         s->array = talloc_array(mem_ctx, uint16_t, val->length/2);
     738         603 :         if (!s->array) {
     739           0 :                 return NT_STATUS_NO_MEMORY;
     740             :         }
     741         603 :         s->length = s->size = val->length;
     742             : 
     743             :         /* The on-disk format is the 'network' format, being UTF16LE (sort of) */
     744        6030 :         for (i = 0; i < s->length / 2; i++) {
     745        5427 :                 s->array[i] = SVAL(val->data, i * 2);
     746             :         }
     747             : 
     748         603 :         return NT_STATUS_OK;
     749             : }
     750             : 
     751             : /* Find an attribute, with a particular value */
     752             : 
     753             : /* The current callers of this function expect a very specific
     754             :  * behaviour: In particular, objectClass subclass equivalence is not
     755             :  * wanted.  This means that we should not lookup the schema for the
     756             :  * comparison function */
     757    58076909 : struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb,
     758             :                                                  const struct ldb_message *msg,
     759             :                                                  const char *name, const char *value)
     760             : {
     761     1126710 :         unsigned int i;
     762    58076909 :         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
     763             : 
     764    58076909 :         if (!el) {
     765         177 :                 return NULL;
     766             :         }
     767             : 
     768   127799011 :         for (i=0;i<el->num_values;i++) {
     769   117243527 :                 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
     770    46905575 :                         return el;
     771             :                 }
     772             :         }
     773             : 
     774    10044447 :         return NULL;
     775             : }
     776             : 
     777      531396 : static int samdb_find_or_add_attribute_ex(struct ldb_context *ldb,
     778             :                                           struct ldb_message *msg,
     779             :                                           const char *name,
     780             :                                           const char *set_value,
     781             :                                           unsigned attr_flags,
     782             :                                           bool *added)
     783             : {
     784       41951 :         int ret;
     785       41951 :         struct ldb_message_element *el;
     786             : 
     787      531396 :         SMB_ASSERT(attr_flags != 0);
     788             : 
     789      531396 :         el = ldb_msg_find_element(msg, name);
     790      531396 :         if (el) {
     791      226858 :                 if (added != NULL) {
     792        2774 :                         *added = false;
     793             :                 }
     794             : 
     795      226858 :                 return LDB_SUCCESS;
     796             :         }
     797             : 
     798      304538 :         ret = ldb_msg_add_empty(msg, name,
     799             :                                 attr_flags,
     800             :                                 &el);
     801      304538 :         if (ret != LDB_SUCCESS) {
     802           0 :                 return ret;
     803             :         }
     804             : 
     805      304538 :         if (set_value != NULL) {
     806      274147 :                 ret = ldb_msg_add_string(msg, name, set_value);
     807      274147 :                 if (ret != LDB_SUCCESS) {
     808           0 :                         return ret;
     809             :                 }
     810             :         }
     811             : 
     812      304538 :         if (added != NULL) {
     813      301876 :                 *added = true;
     814             :         }
     815      302240 :         return LDB_SUCCESS;
     816             : }
     817             : 
     818      226746 : int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
     819             : {
     820      226746 :         return samdb_find_or_add_attribute_ex(ldb, msg, name, set_value, LDB_FLAG_MOD_ADD, NULL);
     821             : }
     822             : 
     823             : /*
     824             :   add a dom_sid element to a message
     825             : */
     826       48658 : int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     827             :                           const char *attr_name, const struct dom_sid *sid)
     828             : {
     829        2179 :         struct ldb_val v;
     830        2179 :         enum ndr_err_code ndr_err;
     831             : 
     832       48658 :         ndr_err = ndr_push_struct_blob(&v, mem_ctx,
     833             :                                        sid,
     834             :                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
     835       48658 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     836           0 :                 return ldb_operr(sam_ldb);
     837             :         }
     838       48658 :         return ldb_msg_add_value(msg, attr_name, &v, NULL);
     839             : }
     840             : 
     841             : 
     842             : /*
     843             :   add a delete element operation to a message
     844             : */
     845        1273 : int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     846             :                          const char *attr_name)
     847             : {
     848             :         /* we use an empty replace rather than a delete, as it allows for
     849             :            dsdb_replace() to be used everywhere */
     850        1273 :         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
     851             : }
     852             : 
     853             : /*
     854             :   add an add attribute value to a message or enhance an existing attribute
     855             :   which has the same name and the add flag set.
     856             : */
     857         259 : int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
     858             :                          struct ldb_message *msg, const char *attr_name,
     859             :                          const char *value)
     860             : {
     861           4 :         struct ldb_message_element *el;
     862           4 :         struct ldb_val val;
     863           4 :         char *v;
     864           4 :         unsigned int i;
     865         259 :         bool found = false;
     866           4 :         int ret;
     867             : 
     868         259 :         v = talloc_strdup(mem_ctx, value);
     869         259 :         if (v == NULL) {
     870           0 :                 return ldb_oom(sam_ldb);
     871             :         }
     872             : 
     873         259 :         val.data = (uint8_t *) v;
     874         259 :         val.length = strlen(v);
     875             : 
     876         259 :         if (val.length == 0) {
     877             :                 /* allow empty strings as non-existent attributes */
     878           0 :                 return LDB_SUCCESS;
     879             :         }
     880             : 
     881         262 :         for (i = 0; i < msg->num_elements; i++) {
     882           3 :                 el = &msg->elements[i];
     883           3 :                 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
     884           0 :                     (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
     885           0 :                         found = true;
     886           0 :                         break;
     887             :                 }
     888             :         }
     889         259 :         if (!found) {
     890         259 :                 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
     891             :                                         &el);
     892         259 :                 if (ret != LDB_SUCCESS) {
     893           0 :                         return ret;
     894             :                 }
     895             :         }
     896             : 
     897         259 :         ret = ldb_msg_element_add_value(msg->elements, el, &val);
     898         259 :         if (ret != LDB_SUCCESS) {
     899           0 :                 return ldb_oom(sam_ldb);
     900             :         }
     901             : 
     902         255 :         return LDB_SUCCESS;
     903             : }
     904             : 
     905             : /*
     906             :   add a delete attribute value to a message or enhance an existing attribute
     907             :   which has the same name and the delete flag set.
     908             : */
     909         249 : int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
     910             :                          struct ldb_message *msg, const char *attr_name,
     911             :                          const char *value)
     912             : {
     913           2 :         struct ldb_message_element *el;
     914           2 :         struct ldb_val val;
     915           2 :         char *v;
     916           2 :         unsigned int i;
     917         249 :         bool found = false;
     918           2 :         int ret;
     919             : 
     920         249 :         v = talloc_strdup(mem_ctx, value);
     921         249 :         if (v == NULL) {
     922           0 :                 return ldb_oom(sam_ldb);
     923             :         }
     924             : 
     925         249 :         val.data = (uint8_t *) v;
     926         249 :         val.length = strlen(v);
     927             : 
     928         249 :         if (val.length == 0) {
     929             :                 /* allow empty strings as non-existent attributes */
     930           0 :                 return LDB_SUCCESS;
     931             :         }
     932             : 
     933         249 :         for (i = 0; i < msg->num_elements; i++) {
     934           0 :                 el = &msg->elements[i];
     935           0 :                 if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
     936           0 :                     (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
     937           0 :                         found = true;
     938           0 :                         break;
     939             :                 }
     940             :         }
     941         249 :         if (!found) {
     942         249 :                 ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
     943             :                                         &el);
     944         249 :                 if (ret != LDB_SUCCESS) {
     945           0 :                         return ret;
     946             :                 }
     947             :         }
     948             : 
     949         249 :         ret = ldb_msg_element_add_value(msg->elements, el, &val);
     950         249 :         if (ret != LDB_SUCCESS) {
     951           0 :                 return ldb_oom(sam_ldb);
     952             :         }
     953             : 
     954         247 :         return LDB_SUCCESS;
     955             : }
     956             : 
     957             : /*
     958             :   add a int element to a message
     959             : */
     960     1264461 : int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     961             :                        const char *attr_name, int v)
     962             : {
     963     1264461 :         const char *s = talloc_asprintf(mem_ctx, "%d", v);
     964     1264461 :         if (s == NULL) {
     965           0 :                 return ldb_oom(sam_ldb);
     966             :         }
     967     1264461 :         return ldb_msg_add_string(msg, attr_name, s);
     968             : }
     969             : 
     970       69276 : int samdb_msg_add_int_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     971             :                             const char *attr_name, int v, int flags)
     972             : {
     973       69276 :         const char *s = talloc_asprintf(mem_ctx, "%d", v);
     974       69276 :         if (s == NULL) {
     975           0 :                 return ldb_oom(sam_ldb);
     976             :         }
     977       69276 :         return ldb_msg_add_string_flags(msg, attr_name, s, flags);
     978             : }
     979             : 
     980             : /*
     981             :  * Add an unsigned int element to a message
     982             :  *
     983             :  * The issue here is that we have not yet first cast to int32_t explicitly,
     984             :  * before we cast to an signed int to printf() into the %d or cast to a
     985             :  * int64_t before we then cast to a long long to printf into a %lld.
     986             :  *
     987             :  * There are *no* unsigned integers in Active Directory LDAP, even the RID
     988             :  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
     989             :  * (See the schema, and the syntax definitions in schema_syntax.c).
     990             :  *
     991             :  */
     992      992155 : int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     993             :                        const char *attr_name, unsigned int v)
     994             : {
     995      992155 :         return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
     996             : }
     997             : 
     998       69276 : int samdb_msg_add_uint_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     999             :                              const char *attr_name, unsigned int v, int flags)
    1000             : {
    1001       69276 :         return samdb_msg_add_int_flags(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags);
    1002             : }
    1003             : 
    1004             : /*
    1005             :   add a (signed) int64_t element to a message
    1006             : */
    1007     3377770 : int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1008             :                         const char *attr_name, int64_t v)
    1009             : {
    1010     3377770 :         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
    1011     3377770 :         if (s == NULL) {
    1012           0 :                 return ldb_oom(sam_ldb);
    1013             :         }
    1014     3377770 :         return ldb_msg_add_string(msg, attr_name, s);
    1015             : }
    1016             : 
    1017             : /*
    1018             :  * Add an unsigned int64_t (uint64_t) element to a message
    1019             :  *
    1020             :  * The issue here is that we have not yet first cast to int32_t explicitly,
    1021             :  * before we cast to an signed int to printf() into the %d or cast to a
    1022             :  * int64_t before we then cast to a long long to printf into a %lld.
    1023             :  *
    1024             :  * There are *no* unsigned integers in Active Directory LDAP, even the RID
    1025             :  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
    1026             :  * (See the schema, and the syntax definitions in schema_syntax.c).
    1027             :  *
    1028             :  */
    1029     2487218 : int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1030             :                         const char *attr_name, uint64_t v)
    1031             : {
    1032     2487218 :         return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
    1033             : }
    1034             : 
    1035             : /*
    1036             :   append a int element to a message
    1037             : */
    1038         724 : int samdb_msg_append_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1039             :                       const char *attr_name, int v, int flags)
    1040             : {
    1041         724 :         const char *s = talloc_asprintf(mem_ctx, "%d", v);
    1042         724 :         if (s == NULL) {
    1043           0 :                 return ldb_oom(sam_ldb);
    1044             :         }
    1045         724 :         return ldb_msg_append_string(msg, attr_name, s, flags);
    1046             : }
    1047             : 
    1048             : /*
    1049             :  * Append an unsigned int element to a message
    1050             :  *
    1051             :  * The issue here is that we have not yet first cast to int32_t explicitly,
    1052             :  * before we cast to an signed int to printf() into the %d or cast to a
    1053             :  * int64_t before we then cast to a long long to printf into a %lld.
    1054             :  *
    1055             :  * There are *no* unsigned integers in Active Directory LDAP, even the RID
    1056             :  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
    1057             :  * (See the schema, and the syntax definitions in schema_syntax.c).
    1058             :  *
    1059             :  */
    1060         598 : int samdb_msg_append_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1061             :                           const char *attr_name, unsigned int v, int flags)
    1062             : {
    1063         598 :         return samdb_msg_append_int(sam_ldb, mem_ctx, msg, attr_name, (int)v, flags);
    1064             : }
    1065             : 
    1066             : /*
    1067             :   append a (signed) int64_t element to a message
    1068             : */
    1069        5606 : int samdb_msg_append_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1070             :                            const char *attr_name, int64_t v, int flags)
    1071             : {
    1072        5606 :         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
    1073        5606 :         if (s == NULL) {
    1074           0 :                 return ldb_oom(sam_ldb);
    1075             :         }
    1076        5606 :         return ldb_msg_append_string(msg, attr_name, s, flags);
    1077             : }
    1078             : 
    1079             : /*
    1080             :  * Append an unsigned int64_t (uint64_t) element to a message
    1081             :  *
    1082             :  * The issue here is that we have not yet first cast to int32_t explicitly,
    1083             :  * before we cast to an signed int to printf() into the %d or cast to a
    1084             :  * int64_t before we then cast to a long long to printf into a %lld.
    1085             :  *
    1086             :  * There are *no* unsigned integers in Active Directory LDAP, even the RID
    1087             :  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
    1088             :  * (See the schema, and the syntax definitions in schema_syntax.c).
    1089             :  *
    1090             :  */
    1091        5606 : int samdb_msg_append_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1092             :                             const char *attr_name, uint64_t v, int flags)
    1093             : {
    1094        5606 :         return samdb_msg_append_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v, flags);
    1095             : }
    1096             : 
    1097             : /*
    1098             :   add a samr_Password element to a message
    1099             : */
    1100       20481 : int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1101             :                        const char *attr_name, const struct samr_Password *hash)
    1102             : {
    1103         211 :         struct ldb_val val;
    1104       20481 :         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
    1105       20481 :         if (!val.data) {
    1106           0 :                 return ldb_oom(sam_ldb);
    1107             :         }
    1108       20481 :         val.length = 16;
    1109       20481 :         return ldb_msg_add_value(msg, attr_name, &val, NULL);
    1110             : }
    1111             : 
    1112             : /*
    1113             :   add a samr_Password array to a message
    1114             : */
    1115       20064 : int samdb_msg_add_hashes(struct ldb_context *ldb,
    1116             :                          TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1117             :                          const char *attr_name, struct samr_Password *hashes,
    1118             :                          unsigned int count)
    1119             : {
    1120         205 :         struct ldb_val val;
    1121         205 :         unsigned int i;
    1122       20064 :         val.data = talloc_array_size(mem_ctx, 16, count);
    1123       20064 :         val.length = count*16;
    1124       20064 :         if (!val.data) {
    1125           0 :                 return ldb_oom(ldb);
    1126             :         }
    1127       53303 :         for (i=0;i<count;i++) {
    1128       33239 :                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
    1129             :         }
    1130       20064 :         return ldb_msg_add_value(msg, attr_name, &val, NULL);
    1131             : }
    1132             : 
    1133             : /*
    1134             :   add a acct_flags element to a message
    1135             : */
    1136         864 : int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1137             :                              const char *attr_name, uint32_t v)
    1138             : {
    1139         864 :         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, ds_acb2uf(v));
    1140             : }
    1141             : 
    1142             : /*
    1143             :   add a logon_hours element to a message
    1144             : */
    1145          99 : int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1146             :                               const char *attr_name, struct samr_LogonHours *hours)
    1147             : {
    1148           0 :         struct ldb_val val;
    1149          99 :         val.length = hours->units_per_week / 8;
    1150          99 :         val.data = hours->bits;
    1151          99 :         return ldb_msg_add_value(msg, attr_name, &val, NULL);
    1152             : }
    1153             : 
    1154             : /*
    1155             :   add a parameters element to a message
    1156             : */
    1157          72 : int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    1158             :                              const char *attr_name, struct lsa_BinaryString *parameters)
    1159             : {
    1160           0 :         int i;
    1161           0 :         struct ldb_val val;
    1162          72 :         if ((parameters->length % 2) != 0) {
    1163           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    1164             :         }
    1165             : 
    1166          72 :         val.data = talloc_array(mem_ctx, uint8_t, parameters->length);
    1167          72 :         if (val.data == NULL) {
    1168           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1169             :         }
    1170          72 :         val.length = parameters->length;
    1171         720 :         for (i = 0; i < parameters->length / 2; i++) {
    1172             :                 /*
    1173             :                  * The on-disk format needs to be in the 'network'
    1174             :                  * format, parameters->array is a uint16_t array of
    1175             :                  * length parameters->length / 2
    1176             :                  */
    1177         648 :                 SSVAL(val.data, i * 2, parameters->array[i]);
    1178             :         }
    1179          72 :         return ldb_msg_add_steal_value(msg, attr_name, &val);
    1180             : }
    1181             : 
    1182             : /*
    1183             :  * Sets an unsigned int element in a message
    1184             :  *
    1185             :  * The issue here is that we have not yet first cast to int32_t explicitly,
    1186             :  * before we cast to an signed int to printf() into the %d or cast to a
    1187             :  * int64_t before we then cast to a long long to printf into a %lld.
    1188             :  *
    1189             :  * There are *no* unsigned integers in Active Directory LDAP, even the RID
    1190             :  * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
    1191             :  * (See the schema, and the syntax definitions in schema_syntax.c).
    1192             :  *
    1193             :  */
    1194       48108 : int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
    1195             :                        struct ldb_message *msg, const char *attr_name,
    1196             :                        unsigned int v)
    1197             : {
    1198         106 :         struct ldb_message_element *el;
    1199             : 
    1200       48108 :         el = ldb_msg_find_element(msg, attr_name);
    1201       48108 :         if (el) {
    1202       24073 :                 el->num_values = 0;
    1203             :         }
    1204       48108 :         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
    1205             : }
    1206             : 
    1207             : /*
    1208             :  * Handle ldb_request in transaction
    1209             :  */
    1210       16065 : int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
    1211             :                                  struct ldb_request *req)
    1212             : {
    1213         258 :         int ret;
    1214             : 
    1215       16065 :         ret = ldb_transaction_start(sam_ldb);
    1216       16065 :         if (ret != LDB_SUCCESS) {
    1217           0 :                 return ret;
    1218             :         }
    1219             : 
    1220       16065 :         ret = ldb_request(sam_ldb, req);
    1221       16065 :         if (ret == LDB_SUCCESS) {
    1222       16065 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    1223             :         }
    1224             : 
    1225       16065 :         if (ret == LDB_SUCCESS) {
    1226       16035 :                 return ldb_transaction_commit(sam_ldb);
    1227             :         }
    1228          30 :         ldb_transaction_cancel(sam_ldb);
    1229             : 
    1230          30 :         return ret;
    1231             : }
    1232             : 
    1233             : /*
    1234             :   return a default security descriptor
    1235             : */
    1236         322 : struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
    1237             : {
    1238           0 :         struct security_descriptor *sd;
    1239             : 
    1240         322 :         sd = security_descriptor_initialise(mem_ctx);
    1241             : 
    1242         322 :         return sd;
    1243             : }
    1244             : 
    1245      181590 : struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
    1246             : {
    1247      181590 :         struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
    1248        6077 :         struct ldb_dn *aggregate_dn;
    1249      181590 :         if (!schema_dn) {
    1250           0 :                 return NULL;
    1251             :         }
    1252             : 
    1253      181590 :         aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
    1254      181590 :         if (!aggregate_dn) {
    1255           0 :                 return NULL;
    1256             :         }
    1257      181590 :         if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
    1258           0 :                 return NULL;
    1259             :         }
    1260      175513 :         return aggregate_dn;
    1261             : }
    1262             : 
    1263      735529 : struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
    1264             : {
    1265       26314 :         struct ldb_dn *new_dn;
    1266             : 
    1267      735529 :         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
    1268      735529 :         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
    1269           0 :                 talloc_free(new_dn);
    1270           0 :                 return NULL;
    1271             :         }
    1272      709215 :         return new_dn;
    1273             : }
    1274             : 
    1275           4 : struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
    1276             : {
    1277           0 :        struct ldb_dn *new_dn;
    1278             : 
    1279           4 :        new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
    1280           4 :        if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
    1281           0 :                talloc_free(new_dn);
    1282           0 :                return NULL;
    1283             :        }
    1284           4 :        return new_dn;
    1285             : }
    1286             : 
    1287      483101 : struct ldb_dn *samdb_system_container_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
    1288             : {
    1289      483101 :         struct ldb_dn *new_dn = NULL;
    1290       17034 :         bool ok;
    1291             : 
    1292      483101 :         new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
    1293      483101 :         if (new_dn == NULL) {
    1294           0 :                 return NULL;
    1295             :         }
    1296             : 
    1297      483101 :         ok = ldb_dn_add_child_fmt(new_dn, "CN=System");
    1298      483101 :         if (!ok) {
    1299           0 :                 TALLOC_FREE(new_dn);
    1300           0 :                 return NULL;
    1301             :         }
    1302             : 
    1303      466067 :         return new_dn;
    1304             : }
    1305             : 
    1306        3528 : struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
    1307             : {
    1308          96 :         struct ldb_dn *new_dn;
    1309             : 
    1310        3528 :         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
    1311        3528 :         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
    1312           0 :                 talloc_free(new_dn);
    1313           0 :                 return NULL;
    1314             :         }
    1315        3432 :         return new_dn;
    1316             : }
    1317             : 
    1318       21277 : struct ldb_dn *samdb_extended_rights_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
    1319             : {
    1320         246 :         struct ldb_dn *new_dn;
    1321             : 
    1322       21277 :         new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
    1323       21277 :         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Extended-Rights")) {
    1324           0 :                 talloc_free(new_dn);
    1325           0 :                 return NULL;
    1326             :         }
    1327       21031 :         return new_dn;
    1328             : }
    1329             : 
    1330         387 : struct ldb_dn *samdb_configuration_dn(struct ldb_context *sam_ctx,
    1331             :                                       TALLOC_CTX *mem_ctx,
    1332             :                                       const char *dn_str)
    1333             : {
    1334         387 :         struct ldb_dn *config_dn = NULL;
    1335         387 :         struct ldb_dn *child_dn = NULL;
    1336          44 :         bool ok;
    1337             : 
    1338         387 :         config_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
    1339         387 :         if (config_dn == NULL) {
    1340           0 :                 return NULL;
    1341             :         }
    1342             : 
    1343         387 :         child_dn = ldb_dn_new(mem_ctx, sam_ctx, dn_str);
    1344         387 :         if (child_dn == NULL) {
    1345           0 :                 talloc_free(config_dn);
    1346           0 :                 return NULL;
    1347             :         }
    1348             : 
    1349         387 :         ok = ldb_dn_add_child(config_dn, child_dn);
    1350         387 :         talloc_free(child_dn);
    1351         387 :         if (!ok) {
    1352           0 :                 talloc_free(config_dn);
    1353           0 :                 return NULL;
    1354             :         }
    1355             : 
    1356         343 :         return config_dn;
    1357             : }
    1358             : 
    1359         287 : struct ldb_dn *samdb_gkdi_root_key_container_dn(struct ldb_context *sam_ctx,
    1360             :                                                 TALLOC_CTX *mem_ctx)
    1361             : {
    1362             :         /*
    1363             :          * [MS-GKDI] says the root key container is to be found in “CN=Sid Key
    1364             :          * Service,CN=Services”, but that is not correct.
    1365             :          */
    1366         287 :         return samdb_configuration_dn(sam_ctx,
    1367             :                                       mem_ctx,
    1368             :                                       "CN=Master Root Keys,"
    1369             :                                       "CN=Group Key Distribution Service,"
    1370             :                                       "CN=Services");
    1371             : }
    1372             : 
    1373         136 : struct ldb_dn *samdb_gkdi_root_key_dn(struct ldb_context *sam_ctx,
    1374             :                                       TALLOC_CTX *mem_ctx,
    1375             :                                       const struct GUID *root_key_id)
    1376             : {
    1377         136 :         struct ldb_dn *root_key_dn = NULL;
    1378         136 :         struct ldb_dn *child_dn = NULL;
    1379          22 :         struct GUID_txt_buf guid_buf;
    1380         136 :         char *root_key_id_string = NULL;
    1381          22 :         bool ok;
    1382             : 
    1383         136 :         root_key_id_string = GUID_buf_string(root_key_id, &guid_buf);
    1384         136 :         if (root_key_id_string == NULL) {
    1385           0 :                 return NULL;
    1386             :         }
    1387             : 
    1388         136 :         root_key_dn = samdb_gkdi_root_key_container_dn(sam_ctx, mem_ctx);
    1389         136 :         if (root_key_dn == NULL) {
    1390           0 :                 return NULL;
    1391             :         }
    1392             : 
    1393         136 :         child_dn = ldb_dn_new_fmt(mem_ctx,
    1394             :                                   sam_ctx,
    1395             :                                   "CN=%s",
    1396             :                                   root_key_id_string);
    1397         136 :         if (child_dn == NULL) {
    1398           0 :                 talloc_free(root_key_dn);
    1399           0 :                 return NULL;
    1400             :         }
    1401             : 
    1402         136 :         ok = ldb_dn_add_child(root_key_dn, child_dn);
    1403         136 :         talloc_free(child_dn);
    1404         136 :         if (!ok) {
    1405           0 :                 talloc_free(root_key_dn);
    1406           0 :                 return NULL;
    1407             :         }
    1408             : 
    1409         114 :         return root_key_dn;
    1410             : }
    1411             : 
    1412             : /*
    1413             :   work out the domain sid for the current open ldb
    1414             : */
    1415     7423314 : const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
    1416             : {
    1417      718808 :         TALLOC_CTX *tmp_ctx;
    1418      718808 :         const struct dom_sid *domain_sid;
    1419     7423314 :         const char *attrs[] = {
    1420             :                 "objectSid",
    1421             :                 NULL
    1422             :         };
    1423      718808 :         struct ldb_result *res;
    1424      718808 :         int ret;
    1425             : 
    1426             :         /* see if we have a cached copy */
    1427     7423314 :         domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
    1428     7423314 :         if (domain_sid) {
    1429     6521041 :                 return domain_sid;
    1430             :         }
    1431             : 
    1432      189677 :         tmp_ctx = talloc_new(ldb);
    1433      189677 :         if (tmp_ctx == NULL) {
    1434           0 :                 goto failed;
    1435             :         }
    1436             : 
    1437      189677 :         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
    1438             : 
    1439      189677 :         if (ret != LDB_SUCCESS) {
    1440         425 :                 goto failed;
    1441             :         }
    1442             : 
    1443      189252 :         if (res->count != 1) {
    1444           0 :                 goto failed;
    1445             :         }
    1446             : 
    1447      189252 :         domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
    1448      189252 :         if (domain_sid == NULL) {
    1449           0 :                 goto failed;
    1450             :         }
    1451             : 
    1452             :         /* cache the domain_sid in the ldb */
    1453      189252 :         if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
    1454           0 :                 goto failed;
    1455             :         }
    1456             : 
    1457      189252 :         talloc_steal(ldb, domain_sid);
    1458      189252 :         talloc_free(tmp_ctx);
    1459             : 
    1460      189252 :         return domain_sid;
    1461             : 
    1462         425 : failed:
    1463         425 :         talloc_free(tmp_ctx);
    1464         425 :         return NULL;
    1465             : }
    1466             : 
    1467             : /*
    1468             :   get domain sid from cache
    1469             : */
    1470       15148 : const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
    1471             : {
    1472       15148 :         return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
    1473             : }
    1474             : 
    1475         127 : bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
    1476             : {
    1477          22 :         TALLOC_CTX *tmp_ctx;
    1478          22 :         struct dom_sid *dom_sid_new;
    1479          22 :         struct dom_sid *dom_sid_old;
    1480             : 
    1481             :         /* see if we have a cached copy */
    1482         127 :         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb,
    1483             :                                                      "cache.domain_sid"), struct dom_sid);
    1484             : 
    1485         127 :         tmp_ctx = talloc_new(ldb);
    1486         127 :         if (tmp_ctx == NULL) {
    1487           0 :                 goto failed;
    1488             :         }
    1489             : 
    1490         127 :         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
    1491         127 :         if (!dom_sid_new) {
    1492           0 :                 goto failed;
    1493             :         }
    1494             : 
    1495             :         /* cache the domain_sid in the ldb */
    1496         127 :         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
    1497           0 :                 goto failed;
    1498             :         }
    1499             : 
    1500         127 :         talloc_steal(ldb, dom_sid_new);
    1501         127 :         talloc_free(tmp_ctx);
    1502         127 :         talloc_free(dom_sid_old);
    1503             : 
    1504         127 :         return true;
    1505             : 
    1506           0 : failed:
    1507           0 :         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
    1508           0 :         talloc_free(tmp_ctx);
    1509           0 :         return false;
    1510             : }
    1511             : 
    1512             : /*
    1513             :   work out the domain guid for the current open ldb
    1514             : */
    1515         147 : const struct GUID *samdb_domain_guid(struct ldb_context *ldb)
    1516             : {
    1517         147 :         TALLOC_CTX *tmp_ctx = NULL;
    1518         147 :         struct GUID *domain_guid = NULL;
    1519         147 :         const char *attrs[] = {
    1520             :                 "objectGUID",
    1521             :                 NULL
    1522             :         };
    1523         147 :         struct ldb_result *res = NULL;
    1524          21 :         int ret;
    1525             : 
    1526             :         /* see if we have a cached copy */
    1527         147 :         domain_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.domain_guid");
    1528         147 :         if (domain_guid) {
    1529           0 :                 return domain_guid;
    1530             :         }
    1531             : 
    1532         147 :         tmp_ctx = talloc_new(ldb);
    1533         147 :         if (tmp_ctx == NULL) {
    1534           0 :                 goto failed;
    1535             :         }
    1536             : 
    1537         147 :         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectGUID=*");
    1538         147 :         if (ret != LDB_SUCCESS) {
    1539           0 :                 goto failed;
    1540             :         }
    1541             : 
    1542         147 :         if (res->count != 1) {
    1543           0 :                 goto failed;
    1544             :         }
    1545             : 
    1546         147 :         domain_guid = talloc(tmp_ctx, struct GUID);
    1547         147 :         if (domain_guid == NULL) {
    1548           0 :                 goto failed;
    1549             :         }
    1550         147 :         *domain_guid = samdb_result_guid(res->msgs[0], "objectGUID");
    1551             : 
    1552             :         /* cache the domain_sid in the ldb */
    1553         147 :         if (ldb_set_opaque(ldb, "cache.domain_guid", domain_guid) != LDB_SUCCESS) {
    1554           0 :                 goto failed;
    1555             :         }
    1556             : 
    1557         147 :         talloc_steal(ldb, domain_guid);
    1558         147 :         talloc_free(tmp_ctx);
    1559             : 
    1560         147 :         return domain_guid;
    1561             : 
    1562           0 : failed:
    1563           0 :         talloc_free(tmp_ctx);
    1564           0 :         return NULL;
    1565             : }
    1566             : 
    1567         342 : bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
    1568             : {
    1569          45 :         TALLOC_CTX *tmp_ctx;
    1570          45 :         struct ldb_dn *ntds_settings_dn_new;
    1571          45 :         struct ldb_dn *ntds_settings_dn_old;
    1572             : 
    1573             :         /* see if we have a forced copy from provision */
    1574         342 :         ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
    1575             :                                                               "forced.ntds_settings_dn"), struct ldb_dn);
    1576             : 
    1577         342 :         tmp_ctx = talloc_new(ldb);
    1578         342 :         if (tmp_ctx == NULL) {
    1579           0 :                 goto failed;
    1580             :         }
    1581             : 
    1582         342 :         ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
    1583         342 :         if (!ntds_settings_dn_new) {
    1584           0 :                 goto failed;
    1585             :         }
    1586             : 
    1587             :         /* set the DN in the ldb to avoid lookups during provision */
    1588         342 :         if (ldb_set_opaque(ldb, "forced.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
    1589           0 :                 goto failed;
    1590             :         }
    1591             : 
    1592         342 :         talloc_steal(ldb, ntds_settings_dn_new);
    1593         342 :         talloc_free(tmp_ctx);
    1594         342 :         talloc_free(ntds_settings_dn_old);
    1595             : 
    1596         342 :         return true;
    1597             : 
    1598           0 : failed:
    1599           0 :         DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
    1600           0 :         talloc_free(tmp_ctx);
    1601           0 :         return false;
    1602             : }
    1603             : 
    1604             : /*
    1605             :   work out the ntds settings dn for the current open ldb
    1606             : */
    1607      436112 : struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
    1608             : {
    1609        5130 :         TALLOC_CTX *tmp_ctx;
    1610      436112 :         const char *root_attrs[] = { "dsServiceName", NULL };
    1611        5130 :         int ret;
    1612        5130 :         struct ldb_result *root_res;
    1613        5130 :         struct ldb_dn *settings_dn;
    1614             : 
    1615             :         /* see if we have a cached copy */
    1616      436112 :         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "forced.ntds_settings_dn");
    1617      436112 :         if (settings_dn) {
    1618        2367 :                 return ldb_dn_copy(mem_ctx, settings_dn);
    1619             :         }
    1620             : 
    1621      433745 :         tmp_ctx = talloc_new(mem_ctx);
    1622      433745 :         if (tmp_ctx == NULL) {
    1623           0 :                 goto failed;
    1624             :         }
    1625             : 
    1626      433745 :         ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
    1627      433745 :         if (ret != LDB_SUCCESS) {
    1628          22 :                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n",
    1629             :                          ldb_errstring(ldb)));
    1630          22 :                 goto failed;
    1631             :         }
    1632             : 
    1633      433723 :         if (root_res->count != 1) {
    1634           0 :                 goto failed;
    1635             :         }
    1636             : 
    1637      433723 :         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
    1638             : 
    1639             :         /* note that we do not cache the DN here, as that would mean
    1640             :          * we could not handle server renames at runtime. Only
    1641             :          * provision sets up forced.ntds_settings_dn */
    1642             : 
    1643      433723 :         talloc_steal(mem_ctx, settings_dn);
    1644      433723 :         talloc_free(tmp_ctx);
    1645             : 
    1646      433723 :         return settings_dn;
    1647             : 
    1648          22 : failed:
    1649          22 :         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
    1650          22 :         talloc_free(tmp_ctx);
    1651          22 :         return NULL;
    1652             : }
    1653             : 
    1654             : /*
    1655             :   work out the ntds settings invocationID/objectGUID for the current open ldb
    1656             : */
    1657     1785914 : static const struct GUID *samdb_ntds_GUID(struct ldb_context *ldb,
    1658             :                                           const char *attribute,
    1659             :                                           const char *cache_name)
    1660             : {
    1661      131729 :         TALLOC_CTX *tmp_ctx;
    1662     1785914 :         const char *attrs[] = { attribute, NULL };
    1663      131729 :         int ret;
    1664      131729 :         struct ldb_result *res;
    1665      131729 :         struct GUID *ntds_guid;
    1666     1785914 :         struct ldb_dn *ntds_settings_dn = NULL;
    1667     1785914 :         const char *errstr = NULL;
    1668             : 
    1669             :         /* see if we have a cached copy */
    1670     1785914 :         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, cache_name);
    1671     1785914 :         if (ntds_guid != NULL) {
    1672     1582343 :                 return ntds_guid;
    1673             :         }
    1674             : 
    1675       73385 :         tmp_ctx = talloc_new(ldb);
    1676       73385 :         if (tmp_ctx == NULL) {
    1677           0 :                 goto failed;
    1678             :         }
    1679             : 
    1680       73385 :         ntds_settings_dn = samdb_ntds_settings_dn(ldb, tmp_ctx);
    1681       73385 :         if (ntds_settings_dn == NULL) {
    1682          19 :                 errstr = "samdb_ntds_settings_dn() returned NULL";
    1683          19 :                 goto failed;
    1684             :         }
    1685             : 
    1686       73366 :         ret = ldb_search(ldb, tmp_ctx, &res, ntds_settings_dn,
    1687             :                          LDB_SCOPE_BASE, attrs, NULL);
    1688       73366 :         if (ret) {
    1689           0 :                 errstr = ldb_errstring(ldb);
    1690           0 :                 goto failed;
    1691             :         }
    1692             : 
    1693       73366 :         if (res->count != 1) {
    1694           0 :                 errstr = "incorrect number of results from base search";
    1695           0 :                 goto failed;
    1696             :         }
    1697             : 
    1698       73366 :         ntds_guid = talloc(tmp_ctx, struct GUID);
    1699       73366 :         if (ntds_guid == NULL) {
    1700           0 :                 goto failed;
    1701             :         }
    1702             : 
    1703       73366 :         *ntds_guid = samdb_result_guid(res->msgs[0], attribute);
    1704             : 
    1705       73366 :         if (GUID_all_zero(ntds_guid)) {
    1706           0 :                 if (ldb_msg_find_ldb_val(res->msgs[0], attribute)) {
    1707           0 :                         errstr = "failed to find the GUID attribute";
    1708             :                 } else {
    1709           0 :                         errstr = "failed to parse the GUID";
    1710             :                 }
    1711           0 :                 goto failed;
    1712             :         }
    1713             : 
    1714             :         /* cache the domain_sid in the ldb */
    1715       73366 :         if (ldb_set_opaque(ldb, cache_name, ntds_guid) != LDB_SUCCESS) {
    1716           0 :                 errstr = "ldb_set_opaque() failed";
    1717           0 :                 goto failed;
    1718             :         }
    1719             : 
    1720       73366 :         talloc_steal(ldb, ntds_guid);
    1721       73366 :         talloc_free(tmp_ctx);
    1722             : 
    1723       73366 :         return ntds_guid;
    1724             : 
    1725          19 : failed:
    1726          19 :         DBG_WARNING("Failed to find our own NTDS Settings %s in the ldb: %s!\n",
    1727             :                     attribute, errstr);
    1728          19 :         talloc_free(tmp_ctx);
    1729          19 :         return NULL;
    1730             : }
    1731             : 
    1732             : /*
    1733             :   work out the ntds settings objectGUID for the current open ldb
    1734             : */
    1735       68567 : const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
    1736             : {
    1737       68567 :         return samdb_ntds_GUID(ldb, "objectGUID", "cache.ntds_guid");
    1738             : }
    1739             : 
    1740             : /*
    1741             :   work out the ntds settings invocationId for the current open ldb
    1742             : */
    1743     1717347 : const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
    1744             : {
    1745     1717347 :         return samdb_ntds_GUID(ldb, "invocationId", "cache.invocation_id");
    1746             : }
    1747             : 
    1748         418 : static bool samdb_set_ntds_GUID(struct ldb_context *ldb,
    1749             :                                 const struct GUID *ntds_guid_in,
    1750             :                                 const char *attribute,
    1751             :                                 const char *cache_name)
    1752             : {
    1753          44 :         TALLOC_CTX *tmp_ctx;
    1754          44 :         struct GUID *ntds_guid_new;
    1755          44 :         struct GUID *ntds_guid_old;
    1756             : 
    1757             :         /* see if we have a cached copy */
    1758         418 :         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, cache_name);
    1759             : 
    1760         418 :         tmp_ctx = talloc_new(ldb);
    1761         418 :         if (tmp_ctx == NULL) {
    1762           0 :                 goto failed;
    1763             :         }
    1764             : 
    1765         418 :         ntds_guid_new = talloc(tmp_ctx, struct GUID);
    1766         418 :         if (!ntds_guid_new) {
    1767           0 :                 goto failed;
    1768             :         }
    1769             : 
    1770         418 :         *ntds_guid_new = *ntds_guid_in;
    1771             : 
    1772             :         /* cache the domain_sid in the ldb */
    1773         418 :         if (ldb_set_opaque(ldb, cache_name, ntds_guid_new) != LDB_SUCCESS) {
    1774           0 :                 goto failed;
    1775             :         }
    1776             : 
    1777         418 :         talloc_steal(ldb, ntds_guid_new);
    1778         418 :         talloc_free(tmp_ctx);
    1779         418 :         talloc_free(ntds_guid_old);
    1780             : 
    1781         418 :         return true;
    1782             : 
    1783           0 : failed:
    1784           0 :         DBG_WARNING("Failed to set our own cached %s in the ldb!\n",
    1785             :                     attribute);
    1786           0 :         talloc_free(tmp_ctx);
    1787           0 :         return false;
    1788             : }
    1789             : 
    1790          76 : bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
    1791             : {
    1792          76 :         return samdb_set_ntds_GUID(ldb,
    1793             :                                    ntds_guid_in,
    1794             :                                    "objectGUID",
    1795             :                                    "cache.ntds_guid");
    1796             : }
    1797             : 
    1798         342 : bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
    1799             : {
    1800         342 :         return samdb_set_ntds_GUID(ldb,
    1801             :                                    invocation_id_in,
    1802             :                                    "invocationId",
    1803             :                                    "cache.invocation_id");
    1804             : }
    1805             : 
    1806             : /*
    1807             :   work out the server dn for the current open ldb
    1808             : */
    1809      122078 : struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
    1810             : {
    1811      122078 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    1812         767 :         struct ldb_dn *dn;
    1813      122078 :         if (!tmp_ctx) {
    1814           0 :                 return NULL;
    1815             :         }
    1816      122078 :         dn = ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb, tmp_ctx));
    1817      122078 :         talloc_free(tmp_ctx);
    1818      122078 :         return dn;
    1819             : 
    1820             : }
    1821             : 
    1822             : /*
    1823             :   work out the server dn for the current open ldb
    1824             : */
    1825       10096 : struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
    1826             : {
    1827         294 :         struct ldb_dn *server_dn;
    1828         294 :         struct ldb_dn *servers_dn;
    1829         294 :         struct ldb_dn *server_site_dn;
    1830             : 
    1831             :         /* TODO: there must be a saner way to do this!! */
    1832       10096 :         server_dn = samdb_server_dn(ldb, mem_ctx);
    1833       10096 :         if (!server_dn) return NULL;
    1834             : 
    1835       10094 :         servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
    1836       10094 :         talloc_free(server_dn);
    1837       10094 :         if (!servers_dn) return NULL;
    1838             : 
    1839       10094 :         server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
    1840       10094 :         talloc_free(servers_dn);
    1841             : 
    1842       10094 :         return server_site_dn;
    1843             : }
    1844             : 
    1845             : /*
    1846             :   find the site name from a computers DN record
    1847             :  */
    1848           5 : int samdb_find_site_for_computer(struct ldb_context *ldb,
    1849             :                                  TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
    1850             :                                  const char **site_name)
    1851             : {
    1852           0 :         int ret;
    1853           0 :         struct ldb_dn *dn;
    1854           0 :         const struct ldb_val *rdn_val;
    1855             : 
    1856           5 :         *site_name = NULL;
    1857             : 
    1858           5 :         ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
    1859           5 :         if (ret != LDB_SUCCESS) {
    1860           0 :                 return ret;
    1861             :         }
    1862             : 
    1863           5 :         if (!ldb_dn_remove_child_components(dn, 2)) {
    1864           0 :                 talloc_free(dn);
    1865           0 :                 return LDB_ERR_INVALID_DN_SYNTAX;
    1866             :         }
    1867             : 
    1868           5 :         rdn_val = ldb_dn_get_rdn_val(dn);
    1869           5 :         if (rdn_val == NULL) {
    1870           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1871             :         }
    1872             : 
    1873           5 :         (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
    1874           5 :         talloc_free(dn);
    1875           5 :         if (!*site_name) {
    1876           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1877             :         }
    1878           5 :         return LDB_SUCCESS;
    1879             : }
    1880             : 
    1881             : /*
    1882             :   find the NTDS GUID from a computers DN record
    1883             :  */
    1884           5 : int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
    1885             :                                      struct GUID *ntds_guid)
    1886             : {
    1887           0 :         int ret;
    1888           0 :         struct ldb_dn *dn;
    1889             : 
    1890           5 :         *ntds_guid = GUID_zero();
    1891             : 
    1892           5 :         ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
    1893           5 :         if (ret != LDB_SUCCESS) {
    1894           0 :                 return ret;
    1895             :         }
    1896             : 
    1897           5 :         if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
    1898           0 :                 talloc_free(dn);
    1899           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1900             :         }
    1901             : 
    1902           5 :         ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
    1903           5 :         talloc_free(dn);
    1904           5 :         return ret;
    1905             : }
    1906             : 
    1907             : /*
    1908             :   find a 'reference' DN that points at another object
    1909             :   (eg. serverReference, rIDManagerReference etc)
    1910             :  */
    1911      224527 : int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
    1912             :                        const char *attribute, struct ldb_dn **dn)
    1913             : {
    1914         729 :         const char *attrs[2];
    1915         729 :         struct ldb_result *res;
    1916         729 :         int ret;
    1917             : 
    1918      224527 :         attrs[0] = attribute;
    1919      224527 :         attrs[1] = NULL;
    1920             : 
    1921      224527 :         ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY|DSDB_SEARCH_SHOW_EXTENDED_DN, NULL);
    1922      224527 :         if (ret != LDB_SUCCESS) {
    1923           0 :                 ldb_asprintf_errstring(ldb, "Cannot find DN %s to get attribute %s for reference dn: %s",
    1924             :                                        ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb));
    1925           0 :                 return ret;
    1926             :         }
    1927             : 
    1928      224527 :         *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
    1929      224527 :         if (!*dn) {
    1930           4 :                 if (!ldb_msg_find_element(res->msgs[0], attribute)) {
    1931           4 :                         ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
    1932             :                                                ldb_dn_get_linearized(base));
    1933             :                 } else {
    1934           0 :                         ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
    1935             :                                                ldb_dn_get_linearized(base));
    1936             :                 }
    1937           4 :                 talloc_free(res);
    1938           4 :                 return LDB_ERR_NO_SUCH_ATTRIBUTE;
    1939             :         }
    1940             : 
    1941      224523 :         talloc_free(res);
    1942      224523 :         return LDB_SUCCESS;
    1943             : }
    1944             : 
    1945             : /*
    1946             :   find if a DN (must have GUID component!) is our ntdsDsa
    1947             :  */
    1948        4617 : int samdb_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *dn, bool *is_ntdsa)
    1949             : {
    1950          82 :         NTSTATUS status;
    1951          82 :         struct GUID dn_guid;
    1952          82 :         const struct GUID *our_ntds_guid;
    1953        4617 :         status = dsdb_get_extended_dn_guid(dn, &dn_guid, "GUID");
    1954        4617 :         if (!NT_STATUS_IS_OK(status)) {
    1955           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1956             :         }
    1957             : 
    1958        4617 :         our_ntds_guid = samdb_ntds_objectGUID(ldb);
    1959        4617 :         if (!our_ntds_guid) {
    1960           0 :                 DEBUG(0, ("Failed to find our NTDS Settings GUID for comparison with %s - %s\n", ldb_dn_get_linearized(dn), ldb_errstring(ldb)));
    1961           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1962             :         }
    1963             : 
    1964        4617 :         *is_ntdsa = GUID_equal(&dn_guid, our_ntds_guid);
    1965        4617 :         return LDB_SUCCESS;
    1966             : }
    1967             : 
    1968             : /*
    1969             :   find a 'reference' DN that points at another object and indicate if it is our ntdsDsa
    1970             :  */
    1971        3958 : int samdb_reference_dn_is_our_ntdsa(struct ldb_context *ldb, struct ldb_dn *base,
    1972             :                                     const char *attribute, bool *is_ntdsa)
    1973             : {
    1974          80 :         int ret;
    1975          80 :         struct ldb_dn *referenced_dn;
    1976        3958 :         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    1977        3958 :         if (tmp_ctx == NULL) {
    1978           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1979             :         }
    1980        3958 :         ret = samdb_reference_dn(ldb, tmp_ctx, base, attribute, &referenced_dn);
    1981        3958 :         if (ret != LDB_SUCCESS) {
    1982           0 :                 DEBUG(0, ("Failed to find object %s for attribute %s - %s\n", ldb_dn_get_linearized(base), attribute, ldb_errstring(ldb)));
    1983           0 :                 return ret;
    1984             :         }
    1985             : 
    1986        3958 :         ret = samdb_dn_is_our_ntdsa(ldb, referenced_dn, is_ntdsa);
    1987             : 
    1988        3958 :         talloc_free(tmp_ctx);
    1989        3958 :         return ret;
    1990             : }
    1991             : 
    1992             : /*
    1993             :   find our machine account via the serverReference attribute in the
    1994             :   server DN
    1995             :  */
    1996      107803 : int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
    1997             : {
    1998         334 :         struct ldb_dn *server_dn;
    1999         334 :         int ret;
    2000             : 
    2001      107803 :         server_dn = samdb_server_dn(ldb, mem_ctx);
    2002      107803 :         if (server_dn == NULL) {
    2003           0 :                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
    2004             :         }
    2005             : 
    2006      107803 :         ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
    2007      107803 :         talloc_free(server_dn);
    2008             : 
    2009      107803 :         return ret;
    2010             : }
    2011             : 
    2012             : /*
    2013             :   find the RID Manager$ DN via the rIDManagerReference attribute in the
    2014             :   base DN
    2015             :  */
    2016         270 : int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
    2017             : {
    2018         270 :         return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
    2019             :                                   "rIDManagerReference", dn);
    2020             : }
    2021             : 
    2022             : /*
    2023             :   find the RID Set DN via the rIDSetReferences attribute in our
    2024             :   machine account DN
    2025             :  */
    2026      107703 : int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
    2027             : {
    2028      107703 :         struct ldb_dn *server_ref_dn = NULL;
    2029         311 :         int ret;
    2030             : 
    2031      107703 :         ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
    2032      107703 :         if (ret != LDB_SUCCESS) {
    2033           0 :                 return ret;
    2034             :         }
    2035      107703 :         ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
    2036      107703 :         talloc_free(server_ref_dn);
    2037      107703 :         return ret;
    2038             : }
    2039             : 
    2040        7881 : const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
    2041             : {
    2042        7881 :         const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
    2043             :                                                                             mem_ctx));
    2044             : 
    2045        7881 :         if (val == NULL) {
    2046           2 :                 return NULL;
    2047             :         }
    2048             : 
    2049        7879 :         return (const char *) val->data;
    2050             : }
    2051             : 
    2052             : /*
    2053             :  * Finds the client site by using the client's IP address.
    2054             :  * The "subnet_name" returns the name of the subnet if parameter != NULL
    2055             :  *
    2056             :  * Has a Windows-based fallback to provide the only site available, or an empty
    2057             :  * string if there are multiple sites.
    2058             :  */
    2059        3620 : const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    2060             :                                    const char *ip_address, char **subnet_name,
    2061             :                                    bool fallback)
    2062             : {
    2063        3620 :         const char *attrs[] = { "cn", "siteObject", NULL };
    2064        3620 :         struct ldb_dn *sites_container_dn = NULL;
    2065        3620 :         struct ldb_dn *subnets_dn = NULL;
    2066        3620 :         struct ldb_dn *sites_dn = NULL;
    2067        3620 :         struct ldb_result *res = NULL;
    2068        3620 :         const struct ldb_val *val = NULL;
    2069        3620 :         const char *site_name = NULL;
    2070        3620 :         const char *l_subnet_name = NULL;
    2071        3620 :         const char *allow_list[2] = { NULL, NULL };
    2072          98 :         unsigned int i, count;
    2073          98 :         int ret;
    2074             : 
    2075             :         /*
    2076             :          * if we don't have a client ip e.g. ncalrpc
    2077             :          * the server site is the client site
    2078             :          */
    2079        3620 :         if (ip_address == NULL) {
    2080          98 :                 return samdb_server_site_name(ldb, mem_ctx);
    2081             :         }
    2082             : 
    2083        3522 :         sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
    2084        3522 :         if (sites_container_dn == NULL) {
    2085           0 :                 goto exit;
    2086             :         }
    2087             : 
    2088        3522 :         subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
    2089        3522 :         if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
    2090           0 :                 goto exit;
    2091             :         }
    2092             : 
    2093        3522 :         ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
    2094             :                          attrs, NULL);
    2095        3522 :         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    2096           0 :                 count = 0;
    2097        3522 :         } else if (ret != LDB_SUCCESS) {
    2098           0 :                 goto exit;
    2099             :         } else {
    2100        3522 :                 count = res->count;
    2101             :         }
    2102             : 
    2103        3522 :         for (i = 0; i < count; i++) {
    2104           0 :                 l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
    2105             :                                                             NULL);
    2106             : 
    2107           0 :                 allow_list[0] = l_subnet_name;
    2108             : 
    2109           0 :                 if (allow_access_nolog(NULL, allow_list, "", ip_address)) {
    2110           0 :                         sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
    2111           0 :                                                            res->msgs[i],
    2112             :                                                            "siteObject");
    2113           0 :                         if (sites_dn == NULL) {
    2114             :                                 /* No reference, maybe another subnet matches */
    2115           0 :                                 continue;
    2116             :                         }
    2117             : 
    2118             :                         /* "val" cannot be NULL here since "sites_dn" != NULL */
    2119           0 :                         val = ldb_dn_get_rdn_val(sites_dn);
    2120           0 :                         site_name = talloc_strdup(mem_ctx,
    2121           0 :                                                   (const char *) val->data);
    2122             : 
    2123           0 :                         TALLOC_FREE(sites_dn);
    2124             : 
    2125           0 :                         break;
    2126             :                 }
    2127             :         }
    2128             : 
    2129        3522 :         if (site_name == NULL && fallback) {
    2130             :                 /* This is the Windows Server fallback rule: when no subnet
    2131             :                  * exists and we have only one site available then use it (it
    2132             :                  * is for sure the same as our server site). If more sites do
    2133             :                  * exist then we don't know which one to use and set the site
    2134             :                  * name to "". */
    2135        3458 :                 size_t cnt = 0;
    2136        3458 :                 ret = dsdb_domain_count(
    2137             :                         ldb,
    2138             :                         &cnt,
    2139             :                         sites_container_dn,
    2140             :                         NULL,
    2141             :                         LDB_SCOPE_SUBTREE,
    2142             :                         "(objectClass=site)");
    2143        3458 :                 if (ret != LDB_SUCCESS) {
    2144           0 :                         goto exit;
    2145             :                 }
    2146        3458 :                 if (cnt == 1) {
    2147        3318 :                         site_name = samdb_server_site_name(ldb, mem_ctx);
    2148             :                 } else {
    2149         140 :                         site_name = talloc_strdup(mem_ctx, "");
    2150             :                 }
    2151        3458 :                 l_subnet_name = NULL;
    2152             :         }
    2153             : 
    2154        3522 :         if (subnet_name != NULL) {
    2155         216 :                 *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
    2156             :         }
    2157             : 
    2158        3306 : exit:
    2159        3522 :         TALLOC_FREE(sites_container_dn);
    2160        3522 :         TALLOC_FREE(subnets_dn);
    2161        3522 :         TALLOC_FREE(res);
    2162             : 
    2163        3426 :         return site_name;
    2164             : }
    2165             : 
    2166             : /*
    2167             :   work out if we are the PDC for the domain of the current open ldb
    2168             : */
    2169        3892 : bool samdb_is_pdc(struct ldb_context *ldb)
    2170             : {
    2171          80 :         int ret;
    2172          80 :         bool is_pdc;
    2173             : 
    2174        3892 :         ret = samdb_reference_dn_is_our_ntdsa(ldb, ldb_get_default_basedn(ldb), "fsmoRoleOwner",
    2175             :                                               &is_pdc);
    2176        3892 :         if (ret != LDB_SUCCESS) {
    2177           0 :                 DEBUG(1,("Failed to find if we are the PDC for this ldb: Searching for fSMORoleOwner in %s failed: %s\n",
    2178             :                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
    2179             :                          ldb_errstring(ldb)));
    2180           0 :                 return false;
    2181             :         }
    2182             : 
    2183        3892 :         return is_pdc;
    2184             : }
    2185             : 
    2186             : /*
    2187             :   work out if we are a Global Catalog server for the domain of the current open ldb
    2188             : */
    2189        4299 : bool samdb_is_gc(struct ldb_context *ldb)
    2190             : {
    2191        4299 :         uint32_t options = 0;
    2192        4299 :         if (samdb_ntds_options(ldb, &options) != LDB_SUCCESS) {
    2193           0 :                 return false;
    2194             :         }
    2195        4299 :         return (options & DS_NTDSDSA_OPT_IS_GC) != 0;
    2196             : }
    2197             : 
    2198             : /* Find a domain object in the parents of a particular DN.  */
    2199          12 : int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
    2200             :                                    struct ldb_dn **parent_dn, const char **errstring)
    2201             : {
    2202           0 :         TALLOC_CTX *local_ctx;
    2203          12 :         struct ldb_dn *sdn = dn;
    2204          12 :         struct ldb_result *res = NULL;
    2205          12 :         int ret = LDB_SUCCESS;
    2206          12 :         const char *attrs[] = { NULL };
    2207             : 
    2208          12 :         local_ctx = talloc_new(mem_ctx);
    2209          12 :         if (local_ctx == NULL) return ldb_oom(ldb);
    2210             : 
    2211          24 :         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
    2212          24 :                 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
    2213             :                                  "(|(objectClass=domain)(objectClass=builtinDomain))");
    2214          24 :                 if (ret == LDB_SUCCESS) {
    2215          24 :                         if (res->count == 1) {
    2216          12 :                                 break;
    2217             :                         }
    2218             :                 } else {
    2219           0 :                         break;
    2220             :                 }
    2221             :         }
    2222             : 
    2223          12 :         if (ret != LDB_SUCCESS) {
    2224           0 :                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
    2225             :                                              ldb_dn_get_linearized(dn),
    2226             :                                              ldb_dn_get_linearized(sdn),
    2227             :                                              ldb_errstring(ldb));
    2228           0 :                 talloc_free(local_ctx);
    2229           0 :                 return ret;
    2230             :         }
    2231             :         /* should never be true with 'ret=LDB_SUCCESS', here to satisfy clang */
    2232          12 :         if (res == NULL) {
    2233           0 :                 talloc_free(local_ctx);
    2234           0 :                 return LDB_ERR_OTHER;
    2235             :         }
    2236          12 :         if (res->count != 1) {
    2237           0 :                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
    2238             :                                              ldb_dn_get_linearized(dn));
    2239           0 :                 DEBUG(0,(__location__ ": %s\n", *errstring));
    2240           0 :                 talloc_free(local_ctx);
    2241           0 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
    2242             :         }
    2243             : 
    2244          12 :         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
    2245          12 :         talloc_free(local_ctx);
    2246          12 :         return ret;
    2247             : }
    2248             : 
    2249           0 : static void pwd_timeout_debug(struct tevent_context *unused1,
    2250             :                               struct tevent_timer *unused2,
    2251             :                               struct timeval unused3,
    2252             :                               void *unused4)
    2253             : {
    2254           0 :         DEBUG(0, ("WARNING: check_password_complexity: password script "
    2255             :                   "took more than 1 second to run\n"));
    2256           0 : }
    2257             : 
    2258             : 
    2259             : /*
    2260             :  * Performs checks on a user password (plaintext UNIX format - attribute
    2261             :  * "password"). The remaining parameters have to be extracted from the domain
    2262             :  * object in the AD.
    2263             :  *
    2264             :  * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
    2265             :  */
    2266       17458 : enum samr_ValidationStatus samdb_check_password(TALLOC_CTX *mem_ctx,
    2267             :                                                 struct loadparm_context *lp_ctx,
    2268             :                                                 const char *account_name,
    2269             :                                                 const char *user_principal_name,
    2270             :                                                 const char *full_name,
    2271             :                                                 const DATA_BLOB *utf8_blob,
    2272             :                                                 const uint32_t pwdProperties,
    2273             :                                                 const uint32_t minPwdLength)
    2274             : {
    2275          56 :         const struct loadparm_substitution *lp_sub =
    2276       17458 :                 lpcfg_noop_substitution();
    2277       17458 :         char *password_script = NULL;
    2278       17458 :         const char *utf8_pw = (const char *)utf8_blob->data;
    2279             : 
    2280             :         /*
    2281             :          * This looks strange because it is.
    2282             :          *
    2283             :          * The check for the number of characters in the password
    2284             :          * should clearly not be against the byte length, or else a
    2285             :          * single UTF8 character would count for more than one.
    2286             :          *
    2287             :          * We have chosen to use the number of 16-bit units that the
    2288             :          * password encodes to as the measure of length.  This is not
    2289             :          * the same as the number of codepoints, if a password
    2290             :          * contains a character beyond the Basic Multilingual Plane
    2291             :          * (above 65535) it will count for more than one "character".
    2292             :          */
    2293             : 
    2294       17458 :         size_t password_characters_roughly = strlen_m(utf8_pw);
    2295             : 
    2296             :         /* checks if the "minPwdLength" property is satisfied */
    2297       17458 :         if (minPwdLength > password_characters_roughly) {
    2298         191 :                 return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
    2299             :         }
    2300             : 
    2301             :         /* We might not be asked to check the password complexity */
    2302       17267 :         if (!(pwdProperties & DOMAIN_PASSWORD_COMPLEX)) {
    2303          83 :                 return SAMR_VALIDATION_STATUS_SUCCESS;
    2304             :         }
    2305             : 
    2306       17184 :         if (password_characters_roughly == 0) {
    2307           0 :                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
    2308             :         }
    2309             : 
    2310       17184 :         password_script = lpcfg_check_password_script(lp_ctx, lp_sub, mem_ctx);
    2311       17184 :         if (password_script != NULL && *password_script != '\0') {
    2312          23 :                 int check_ret = 0;
    2313          23 :                 int error = 0;
    2314          23 :                 ssize_t nwritten = 0;
    2315          23 :                 struct tevent_context *event_ctx = NULL;
    2316          23 :                 struct tevent_req *req = NULL;
    2317          23 :                 int cps_stdin = -1;
    2318          23 :                 const char * const cmd[4] = {
    2319             :                         "/bin/sh", "-c",
    2320             :                         password_script,
    2321             :                         NULL
    2322             :                 };
    2323             : 
    2324          23 :                 event_ctx = tevent_context_init(mem_ctx);
    2325          23 :                 if (event_ctx == NULL) {
    2326           0 :                         TALLOC_FREE(password_script);
    2327           0 :                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
    2328             :                 }
    2329             : 
    2330             :                 /* Gives a warning after 1 second, terminates after 10 */
    2331          23 :                 tevent_add_timer(event_ctx, event_ctx,
    2332             :                                  tevent_timeval_current_ofs(1, 0),
    2333             :                                  pwd_timeout_debug, NULL);
    2334             : 
    2335          23 :                 check_ret = setenv("SAMBA_CPS_ACCOUNT_NAME", account_name, 1);
    2336          23 :                 if (check_ret != 0) {
    2337           0 :                         TALLOC_FREE(password_script);
    2338           0 :                         TALLOC_FREE(event_ctx);
    2339           0 :                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
    2340             :                 }
    2341          23 :                 if (user_principal_name != NULL) {
    2342          20 :                         check_ret = setenv("SAMBA_CPS_USER_PRINCIPAL_NAME",
    2343             :                                            user_principal_name, 1);
    2344             :                 } else {
    2345           3 :                         unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
    2346             :                 }
    2347          23 :                 if (check_ret != 0) {
    2348           0 :                         TALLOC_FREE(password_script);
    2349           0 :                         TALLOC_FREE(event_ctx);
    2350           0 :                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
    2351             :                 }
    2352          23 :                 if (full_name != NULL) {
    2353           0 :                         check_ret = setenv("SAMBA_CPS_FULL_NAME", full_name, 1);
    2354             :                 } else {
    2355          23 :                         unsetenv("SAMBA_CPS_FULL_NAME");
    2356             :                 }
    2357          23 :                 if (check_ret != 0) {
    2358           0 :                         TALLOC_FREE(password_script);
    2359           0 :                         TALLOC_FREE(event_ctx);
    2360           0 :                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
    2361             :                 }
    2362             : 
    2363          23 :                 req = samba_runcmd_send(event_ctx, event_ctx,
    2364             :                                         tevent_timeval_current_ofs(10, 0),
    2365             :                                         100, 100, cmd, NULL);
    2366          23 :                 unsetenv("SAMBA_CPS_ACCOUNT_NAME");
    2367          23 :                 unsetenv("SAMBA_CPS_USER_PRINCIPAL_NAME");
    2368          23 :                 unsetenv("SAMBA_CPS_FULL_NAME");
    2369          23 :                 if (req == NULL) {
    2370           0 :                         TALLOC_FREE(password_script);
    2371           0 :                         TALLOC_FREE(event_ctx);
    2372           0 :                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
    2373             :                 }
    2374             : 
    2375          23 :                 cps_stdin = samba_runcmd_export_stdin(req);
    2376             : 
    2377          23 :                 nwritten = write_data(
    2378          23 :                         cps_stdin, utf8_blob->data, utf8_blob->length);
    2379          23 :                 if (nwritten == -1) {
    2380           0 :                         close(cps_stdin);
    2381           0 :                         TALLOC_FREE(password_script);
    2382           0 :                         TALLOC_FREE(event_ctx);
    2383           0 :                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
    2384             :                 }
    2385             : 
    2386          23 :                 close(cps_stdin);
    2387             : 
    2388          23 :                 if (!tevent_req_poll(req, event_ctx)) {
    2389           0 :                         TALLOC_FREE(password_script);
    2390           0 :                         TALLOC_FREE(event_ctx);
    2391           0 :                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
    2392             :                 }
    2393             : 
    2394          23 :                 check_ret = samba_runcmd_recv(req, &error);
    2395          23 :                 TALLOC_FREE(event_ctx);
    2396             : 
    2397          23 :                 if (error == ETIMEDOUT) {
    2398           0 :                         DEBUG(0, ("check_password_complexity: check password script took too long!\n"));
    2399           0 :                         TALLOC_FREE(password_script);
    2400           0 :                         return SAMR_VALIDATION_STATUS_PASSWORD_FILTER_ERROR;
    2401             :                 }
    2402          23 :                 DEBUG(5,("check_password_complexity: check password script (%s) "
    2403             :                          "returned [%d]\n", password_script, check_ret));
    2404             : 
    2405          23 :                 if (check_ret != 0) {
    2406           6 :                         DEBUG(1,("check_password_complexity: "
    2407             :                                  "check password script said new password is not good "
    2408             :                                  "enough!\n"));
    2409           6 :                         TALLOC_FREE(password_script);
    2410           6 :                         return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
    2411             :                 }
    2412             : 
    2413          17 :                 TALLOC_FREE(password_script);
    2414          17 :                 return SAMR_VALIDATION_STATUS_SUCCESS;
    2415             :         }
    2416             : 
    2417       17161 :         TALLOC_FREE(password_script);
    2418             : 
    2419             :         /*
    2420             :          * Here are the standard AD password quality rules, which we
    2421             :          * run after the script.
    2422             :          */
    2423             : 
    2424       17161 :         if (!check_password_quality(utf8_pw)) {
    2425          47 :                 return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
    2426             :         }
    2427             : 
    2428       17058 :         return SAMR_VALIDATION_STATUS_SUCCESS;
    2429             : }
    2430             : 
    2431             : /*
    2432             :  * Callback for "samdb_set_password" password change
    2433             :  */
    2434        2124 : int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
    2435             : {
    2436         103 :         int ret;
    2437             : 
    2438        2124 :         if (!ares) {
    2439           0 :                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    2440             :         }
    2441             : 
    2442        2124 :         if (ares->error != LDB_SUCCESS) {
    2443         204 :                 ret = ares->error;
    2444         204 :                 req->context = talloc_steal(req,
    2445             :                                             ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
    2446         204 :                 talloc_free(ares);
    2447         204 :                 return ldb_request_done(req, ret);
    2448             :         }
    2449             : 
    2450        1920 :         if (ares->type != LDB_REPLY_DONE) {
    2451           0 :                 talloc_free(ares);
    2452           0 :                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    2453             :         }
    2454             : 
    2455        1920 :         req->context = talloc_steal(req,
    2456             :                                     ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
    2457        1920 :         talloc_free(ares);
    2458        1920 :         return ldb_request_done(req, LDB_SUCCESS);
    2459             : }
    2460             : 
    2461        2138 : static NTSTATUS samdb_set_password_request(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    2462             :                             struct ldb_dn *user_dn,
    2463             :                             const DATA_BLOB *new_password,
    2464             :                             const struct samr_Password *ntNewHash,
    2465             :                             enum dsdb_password_checked old_password_checked,
    2466             :                             bool permit_interdomain_trust,
    2467             :                             struct ldb_request **req_out)
    2468             : {
    2469         103 :         struct ldb_message *msg;
    2470         103 :         struct ldb_message_element *el;
    2471         103 :         struct ldb_request *req;
    2472         103 :         int ret;
    2473        2138 :         bool hash_values = false;
    2474             : 
    2475        2138 :         *req_out = NULL;
    2476             : 
    2477             : #define CHECK_RET(x) \
    2478             :         if (x != LDB_SUCCESS) { \
    2479             :                 talloc_free(msg); \
    2480             :                 return NT_STATUS_NO_MEMORY; \
    2481             :         }
    2482             : 
    2483        2138 :         msg = ldb_msg_new(mem_ctx);
    2484        2138 :         if (msg == NULL) {
    2485           0 :                 return NT_STATUS_NO_MEMORY;
    2486             :         }
    2487        2138 :         msg->dn = user_dn;
    2488        2138 :         if ((new_password != NULL)
    2489        1784 :                         && ((ntNewHash == NULL))) {
    2490             :                 /* we have the password as plaintext UTF16 */
    2491        1778 :                 CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
    2492          97 :                                             new_password, NULL));
    2493        1778 :                 el = ldb_msg_find_element(msg, "clearTextPassword");
    2494        1778 :                 el->flags = LDB_FLAG_MOD_REPLACE;
    2495         360 :         } else if ((new_password == NULL)
    2496         360 :                         && ((ntNewHash != NULL))) {
    2497             :                 /* we have a password as NT hash */
    2498         360 :                 if (ntNewHash != NULL) {
    2499         360 :                         CHECK_RET(samdb_msg_add_hash(ldb, msg, msg,
    2500           6 :                                 "unicodePwd", ntNewHash));
    2501         360 :                         el = ldb_msg_find_element(msg, "unicodePwd");
    2502         360 :                         el->flags = LDB_FLAG_MOD_REPLACE;
    2503             :                 }
    2504         360 :                 hash_values = true;
    2505             :         } else {
    2506             :                 /* the password wasn't specified correctly */
    2507           0 :                 talloc_free(msg);
    2508           0 :                 return NT_STATUS_INVALID_PARAMETER;
    2509             :         }
    2510             : 
    2511             : #undef CHECK_RET
    2512             : 
    2513             :         /* build modify request */
    2514        2138 :         ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
    2515             :                                 samdb_set_password_callback, NULL);
    2516        2138 :         if (ret != LDB_SUCCESS) {
    2517           0 :                 talloc_free(msg);
    2518           0 :                 return NT_STATUS_NO_MEMORY;
    2519             :         }
    2520             : 
    2521             :         /* Tie the lifetime of the message to that of the request. */
    2522        2138 :         talloc_steal(req, msg);
    2523             : 
    2524             :         /* A password change operation */
    2525        2138 :         if (old_password_checked == DSDB_PASSWORD_CHECKED_AND_CORRECT) {
    2526          31 :                 struct dsdb_control_password_change *change;
    2527             : 
    2528         883 :                 change = talloc(req, struct dsdb_control_password_change);
    2529         883 :                 if (change == NULL) {
    2530           0 :                         talloc_free(req);
    2531           0 :                         return NT_STATUS_NO_MEMORY;
    2532             :                 }
    2533             : 
    2534         883 :                 change->old_password_checked = old_password_checked;
    2535             : 
    2536         883 :                 ret = ldb_request_add_control(req,
    2537             :                                               DSDB_CONTROL_PASSWORD_CHANGE_OLD_PW_CHECKED_OID,
    2538             :                                               true, change);
    2539         883 :                 if (ret != LDB_SUCCESS) {
    2540           0 :                         talloc_free(req);
    2541           0 :                         return NT_STATUS_NO_MEMORY;
    2542             :                 }
    2543             :         }
    2544        2138 :         if (hash_values) {
    2545         360 :                 ret = ldb_request_add_control(req,
    2546             :                                               DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
    2547             :                                               true, NULL);
    2548         360 :                 if (ret != LDB_SUCCESS) {
    2549           0 :                         talloc_free(req);
    2550           0 :                         return NT_STATUS_NO_MEMORY;
    2551             :                 }
    2552             :         }
    2553        2138 :         if (permit_interdomain_trust) {
    2554         414 :                 ret = ldb_request_add_control(req,
    2555             :                                               DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
    2556             :                                               false, NULL);
    2557         414 :                 if (ret != LDB_SUCCESS) {
    2558           0 :                         talloc_free(req);
    2559           0 :                         return NT_STATUS_NO_MEMORY;
    2560             :                 }
    2561             :         }
    2562        2138 :         ret = ldb_request_add_control(req,
    2563             :                                       DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
    2564             :                                       true, NULL);
    2565        2138 :         if (ret != LDB_SUCCESS) {
    2566           0 :                 talloc_free(req);
    2567           0 :                 return NT_STATUS_NO_MEMORY;
    2568             :         }
    2569             : 
    2570        2138 :         *req_out = req;
    2571             : 
    2572        2138 :         return NT_STATUS_OK;
    2573             : }
    2574             : 
    2575             : /*
    2576             :  * Sets the user password using plaintext UTF16 (attribute "new_password") or NT
    2577             :  * (attribute "ntNewHash") hash. Also pass the old LM and/or NT hash (attributes
    2578             :  * "lmOldHash"/"ntOldHash") if it is a user change or not. The "rejectReason"
    2579             :  * gives some more information if the change failed.
    2580             :  *
    2581             :  * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
    2582             :  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
    2583             :  *   NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCOUNT_LOCKED_OUT, NT_STATUS_NO_MEMORY
    2584             :  */
    2585        2093 : static NTSTATUS samdb_set_password_internal(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    2586             :                             struct ldb_dn *user_dn,
    2587             :                             const DATA_BLOB *new_password,
    2588             :                             const struct samr_Password *ntNewHash,
    2589             :                             enum dsdb_password_checked old_password_checked,
    2590             :                             enum samPwdChangeReason *reject_reason,
    2591             :                             struct samr_DomInfo1 **_dominfo,
    2592             :                             bool permit_interdomain_trust)
    2593             : {
    2594         103 :         struct ldb_request *req;
    2595        2093 :         struct dsdb_control_password_change_status *pwd_stat = NULL;
    2596         103 :         int ret;
    2597        2093 :         NTSTATUS status = NT_STATUS_OK;
    2598             : 
    2599        2093 :         status = samdb_set_password_request(ldb,
    2600             :                                             mem_ctx,
    2601             :                                             user_dn,
    2602             :                                             new_password,
    2603             :                                             ntNewHash,
    2604             :                                             old_password_checked,
    2605             :                                             permit_interdomain_trust,
    2606             :                                             &req);
    2607        2093 :         if (!NT_STATUS_IS_OK(status)) {
    2608           0 :                 return status;
    2609             :         }
    2610             : 
    2611        2093 :         ret = ldb_request(ldb, req);
    2612        2093 :         if (ret == LDB_SUCCESS) {
    2613        2077 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    2614             :         }
    2615             : 
    2616        2093 :         if (req->context != NULL) {
    2617        2077 :                 struct ldb_control *control = talloc_get_type_abort(req->context,
    2618             :                                                                     struct ldb_control);
    2619        2077 :                 pwd_stat = talloc_get_type_abort(control->data,
    2620             :                                                  struct dsdb_control_password_change_status);
    2621        2077 :                 talloc_steal(mem_ctx, pwd_stat);
    2622             :         }
    2623             : 
    2624        2093 :         talloc_free(req);
    2625             : 
    2626             :         /* Sets the domain info (if requested) */
    2627        2093 :         if (_dominfo != NULL) {
    2628           0 :                 struct samr_DomInfo1 *dominfo;
    2629             : 
    2630         467 :                 dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
    2631         467 :                 if (dominfo == NULL) {
    2632           0 :                         return NT_STATUS_NO_MEMORY;
    2633             :                 }
    2634             : 
    2635         467 :                 if (pwd_stat != NULL) {
    2636         452 :                         dominfo->min_password_length     = pwd_stat->domain_data.minPwdLength;
    2637         452 :                         dominfo->password_properties     = pwd_stat->domain_data.pwdProperties;
    2638         452 :                         dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
    2639         452 :                         dominfo->max_password_age        = pwd_stat->domain_data.maxPwdAge;
    2640         452 :                         dominfo->min_password_age        = pwd_stat->domain_data.minPwdAge;
    2641             :                 }
    2642             : 
    2643         467 :                 *_dominfo = dominfo;
    2644             :         }
    2645             : 
    2646        2093 :         if (reject_reason != NULL) {
    2647         467 :                 if (pwd_stat != NULL) {
    2648         452 :                         *reject_reason = pwd_stat->reject_reason;
    2649             :                 } else {
    2650          15 :                         *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
    2651             :                 }
    2652             :         }
    2653             : 
    2654        2093 :         if (pwd_stat != NULL) {
    2655        2077 :                 talloc_free(pwd_stat);
    2656             :         }
    2657             : 
    2658        2093 :         if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
    2659         188 :                 const char *errmsg = ldb_errstring(ldb);
    2660         188 :                 char *endptr = NULL;
    2661         188 :                 WERROR werr = WERR_GEN_FAILURE;
    2662         188 :                 status = NT_STATUS_UNSUCCESSFUL;
    2663         188 :                 if (errmsg != NULL) {
    2664         188 :                         werr = W_ERROR(strtol(errmsg, &endptr, 16));
    2665         188 :                         DBG_WARNING("%s\n", errmsg);
    2666             :                 }
    2667         188 :                 if (endptr != errmsg) {
    2668         188 :                         if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
    2669           0 :                                 status = NT_STATUS_WRONG_PASSWORD;
    2670             :                         }
    2671         188 :                         if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
    2672         188 :                                 status = NT_STATUS_PASSWORD_RESTRICTION;
    2673             :                         }
    2674         188 :                         if (W_ERROR_EQUAL(werr, WERR_ACCOUNT_LOCKED_OUT)) {
    2675           0 :                                 status = NT_STATUS_ACCOUNT_LOCKED_OUT;
    2676             :                         }
    2677             :                 }
    2678        1905 :         } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    2679             :                 /* don't let the caller know if an account doesn't exist */
    2680           0 :                 status = NT_STATUS_WRONG_PASSWORD;
    2681        1802 :         } else if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    2682          16 :                 status = NT_STATUS_ACCESS_DENIED;
    2683        1786 :         } else if (ret != LDB_SUCCESS) {
    2684           0 :                 DEBUG(1, ("Failed to set password on %s: %s\n",
    2685             :                           ldb_dn_get_linearized(user_dn),
    2686             :                           ldb_errstring(ldb)));
    2687           0 :                 status = NT_STATUS_UNSUCCESSFUL;
    2688             :         }
    2689             : 
    2690        2093 :         return status;
    2691             : }
    2692             : 
    2693        1679 : NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    2694             :                             struct ldb_dn *user_dn,
    2695             :                             const DATA_BLOB *new_password,
    2696             :                             const struct samr_Password *ntNewHash,
    2697             :                             enum dsdb_password_checked old_password_checked,
    2698             :                             enum samPwdChangeReason *reject_reason,
    2699             :                             struct samr_DomInfo1 **_dominfo)
    2700             : {
    2701        1679 :         return samdb_set_password_internal(ldb, mem_ctx,
    2702             :                             user_dn,
    2703             :                             new_password,
    2704             :                             ntNewHash,
    2705             :                             old_password_checked,
    2706             :                             reject_reason, _dominfo,
    2707             :                             false); /* reject trusts */
    2708             : }
    2709             : 
    2710             : /*
    2711             :  * Sets the user password using plaintext UTF16 (attribute "new_password") or NT
    2712             :  * (attribute "ntNewHash") hash. Also pass the old LM and/or NT hash (attributes
    2713             :  * "lmOldHash"/"ntOldHash") if it is a user change or not. The "rejectReason"
    2714             :  * gives some more information if the change failed.
    2715             :  *
    2716             :  * This wrapper function for "samdb_set_password" takes a SID as input rather
    2717             :  * than a user DN.
    2718             :  *
    2719             :  * This call encapsulates a new LDB transaction for changing the password;
    2720             :  * therefore the user hasn't to start a new one.
    2721             :  *
    2722             :  * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
    2723             :  *   NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
    2724             :  *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
    2725             :  *   NT_STATUS_ACCESS_DENIED, NT_STATUS_ACCOUNT_LOCKED_OUT, NT_STATUS_NO_MEMORY
    2726             :  *   NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
    2727             :  */
    2728         414 : NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    2729             :                                 const struct dom_sid *user_sid,
    2730             :                                 const uint32_t *new_version, /* optional for trusts */
    2731             :                                 const DATA_BLOB *new_password,
    2732             :                                 const struct samr_Password *ntNewHash,
    2733             :                                 enum dsdb_password_checked old_password_checked,
    2734             :                                 enum samPwdChangeReason *reject_reason,
    2735             :                                 struct samr_DomInfo1 **_dominfo)
    2736             : {
    2737         414 :         TALLOC_CTX *frame = talloc_stackframe();
    2738          31 :         NTSTATUS nt_status;
    2739          31 :         static const char * const attrs[] = {
    2740             :                 "userAccountControl",
    2741             :                 "sAMAccountName",
    2742             :                 NULL
    2743             :         };
    2744         414 :         struct ldb_message *user_msg = NULL;
    2745          31 :         int ret;
    2746         414 :         uint32_t uac = 0;
    2747             : 
    2748         414 :         ret = ldb_transaction_start(ldb);
    2749         414 :         if (ret != LDB_SUCCESS) {
    2750           0 :                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
    2751           0 :                 TALLOC_FREE(frame);
    2752           0 :                 return NT_STATUS_TRANSACTION_ABORTED;
    2753             :         }
    2754             : 
    2755         414 :         ret = dsdb_search_one(ldb, frame, &user_msg, ldb_get_default_basedn(ldb),
    2756             :                               LDB_SCOPE_SUBTREE, attrs, 0,
    2757             :                               "(&(objectSid=%s)(objectClass=user))",
    2758             :                               ldap_encode_ndr_dom_sid(frame, user_sid));
    2759         414 :         if (ret != LDB_SUCCESS) {
    2760           0 :                 ldb_transaction_cancel(ldb);
    2761           0 :                 DEBUG(3, ("samdb_set_password_sid: SID[%s] not found in samdb %s - %s, "
    2762             :                           "returning NO_SUCH_USER\n",
    2763             :                           dom_sid_string(frame, user_sid),
    2764             :                           ldb_strerror(ret), ldb_errstring(ldb)));
    2765           0 :                 TALLOC_FREE(frame);
    2766           0 :                 return NT_STATUS_NO_SUCH_USER;
    2767             :         }
    2768             : 
    2769         414 :         uac = ldb_msg_find_attr_as_uint(user_msg, "userAccountControl", 0);
    2770         414 :         if (!(uac & UF_ACCOUNT_TYPE_MASK)) {
    2771           0 :                 ldb_transaction_cancel(ldb);
    2772           0 :                 DEBUG(1, ("samdb_set_password_sid: invalid "
    2773             :                           "userAccountControl[0x%08X] for SID[%s] DN[%s], "
    2774             :                           "returning NO_SUCH_USER\n",
    2775             :                           (unsigned)uac, dom_sid_string(frame, user_sid),
    2776             :                           ldb_dn_get_linearized(user_msg->dn)));
    2777           0 :                 TALLOC_FREE(frame);
    2778           0 :                 return NT_STATUS_NO_SUCH_USER;
    2779             :         }
    2780             : 
    2781         414 :         if (uac & UF_INTERDOMAIN_TRUST_ACCOUNT) {
    2782           0 :                 static const char * const tdo_attrs[] = {
    2783             :                         "trustAuthIncoming",
    2784             :                         "trustDirection",
    2785             :                         NULL
    2786             :                 };
    2787         114 :                 struct ldb_message *tdo_msg = NULL;
    2788         114 :                 const char *account_name = NULL;
    2789           0 :                 uint32_t trust_direction;
    2790           0 :                 uint32_t i;
    2791         114 :                 const struct ldb_val *old_val = NULL;
    2792         114 :                 struct trustAuthInOutBlob old_blob = {
    2793             :                         .count = 0,
    2794             :                 };
    2795         114 :                 uint32_t old_version = 0;
    2796         114 :                 struct AuthenticationInformation *old_version_a = NULL;
    2797         114 :                 uint32_t _new_version = 0;
    2798         114 :                 struct trustAuthInOutBlob new_blob = {
    2799             :                         .count = 0,
    2800             :                 };
    2801         114 :                 struct ldb_val new_val = {
    2802             :                         .length = 0,
    2803             :                 };
    2804         114 :                 struct timeval tv = timeval_current();
    2805         114 :                 NTTIME now = timeval_to_nttime(&tv);
    2806           0 :                 enum ndr_err_code ndr_err;
    2807             : 
    2808         114 :                 if (new_password == NULL && ntNewHash == NULL) {
    2809           0 :                         ldb_transaction_cancel(ldb);
    2810           0 :                         DEBUG(1, ("samdb_set_password_sid: "
    2811             :                                   "no new password provided "
    2812             :                                   "sAMAccountName for SID[%s] DN[%s], "
    2813             :                                   "returning INVALID_PARAMETER\n",
    2814             :                                   dom_sid_string(frame, user_sid),
    2815             :                                   ldb_dn_get_linearized(user_msg->dn)));
    2816           0 :                         TALLOC_FREE(frame);
    2817           0 :                         return NT_STATUS_INVALID_PARAMETER;
    2818             :                 }
    2819             : 
    2820         114 :                 if (new_password != NULL && ntNewHash != NULL) {
    2821           0 :                         ldb_transaction_cancel(ldb);
    2822           0 :                         DEBUG(1, ("samdb_set_password_sid: "
    2823             :                                   "two new passwords provided "
    2824             :                                   "sAMAccountName for SID[%s] DN[%s], "
    2825             :                                   "returning INVALID_PARAMETER\n",
    2826             :                                   dom_sid_string(frame, user_sid),
    2827             :                                   ldb_dn_get_linearized(user_msg->dn)));
    2828           0 :                         TALLOC_FREE(frame);
    2829           0 :                         return NT_STATUS_INVALID_PARAMETER;
    2830             :                 }
    2831             : 
    2832         114 :                 if (new_password != NULL && (new_password->length % 2)) {
    2833           0 :                         ldb_transaction_cancel(ldb);
    2834           0 :                         DEBUG(2, ("samdb_set_password_sid: "
    2835             :                                   "invalid utf16 length (%zu) "
    2836             :                                   "sAMAccountName for SID[%s] DN[%s], "
    2837             :                                   "returning WRONG_PASSWORD\n",
    2838             :                                   new_password->length,
    2839             :                                   dom_sid_string(frame, user_sid),
    2840             :                                   ldb_dn_get_linearized(user_msg->dn)));
    2841           0 :                         TALLOC_FREE(frame);
    2842           0 :                         return NT_STATUS_WRONG_PASSWORD;
    2843             :                 }
    2844             : 
    2845         114 :                 if (new_password != NULL && new_password->length >= 500) {
    2846           0 :                         ldb_transaction_cancel(ldb);
    2847           0 :                         DEBUG(2, ("samdb_set_password_sid: "
    2848             :                                   "utf16 password too long (%zu) "
    2849             :                                   "sAMAccountName for SID[%s] DN[%s], "
    2850             :                                   "returning WRONG_PASSWORD\n",
    2851             :                                   new_password->length,
    2852             :                                   dom_sid_string(frame, user_sid),
    2853             :                                   ldb_dn_get_linearized(user_msg->dn)));
    2854           0 :                         TALLOC_FREE(frame);
    2855           0 :                         return NT_STATUS_WRONG_PASSWORD;
    2856             :                 }
    2857             : 
    2858         114 :                 account_name = ldb_msg_find_attr_as_string(user_msg,
    2859             :                                                         "sAMAccountName", NULL);
    2860         114 :                 if (account_name == NULL) {
    2861           0 :                         ldb_transaction_cancel(ldb);
    2862           0 :                         DEBUG(1, ("samdb_set_password_sid: missing "
    2863             :                                   "sAMAccountName for SID[%s] DN[%s], "
    2864             :                                   "returning NO_SUCH_USER\n",
    2865             :                                   dom_sid_string(frame, user_sid),
    2866             :                                   ldb_dn_get_linearized(user_msg->dn)));
    2867           0 :                         TALLOC_FREE(frame);
    2868           0 :                         return NT_STATUS_NO_SUCH_USER;
    2869             :                 }
    2870             : 
    2871         114 :                 nt_status = dsdb_trust_search_tdo_by_type(ldb,
    2872             :                                                           SEC_CHAN_DOMAIN,
    2873             :                                                           account_name,
    2874             :                                                           tdo_attrs,
    2875             :                                                           frame, &tdo_msg);
    2876         114 :                 if (!NT_STATUS_IS_OK(nt_status)) {
    2877           0 :                         ldb_transaction_cancel(ldb);
    2878           0 :                         DEBUG(1, ("samdb_set_password_sid: dsdb_trust_search_tdo "
    2879             :                                   "failed(%s) for sAMAccountName[%s] SID[%s] DN[%s], "
    2880             :                                   "returning INTERNAL_DB_CORRUPTION\n",
    2881             :                                   nt_errstr(nt_status), account_name,
    2882             :                                   dom_sid_string(frame, user_sid),
    2883             :                                   ldb_dn_get_linearized(user_msg->dn)));
    2884           0 :                         TALLOC_FREE(frame);
    2885           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2886             :                 }
    2887             : 
    2888         114 :                 trust_direction = ldb_msg_find_attr_as_int(tdo_msg,
    2889             :                                                            "trustDirection", 0);
    2890         114 :                 if (!(trust_direction & LSA_TRUST_DIRECTION_INBOUND)) {
    2891           0 :                         ldb_transaction_cancel(ldb);
    2892           0 :                         DEBUG(1, ("samdb_set_password_sid: direction[0x%08X] is "
    2893             :                                   "not inbound for sAMAccountName[%s] "
    2894             :                                   "DN[%s] TDO[%s], "
    2895             :                                   "returning INTERNAL_DB_CORRUPTION\n",
    2896             :                                   (unsigned)trust_direction,
    2897             :                                   account_name,
    2898             :                                   ldb_dn_get_linearized(user_msg->dn),
    2899             :                                   ldb_dn_get_linearized(tdo_msg->dn)));
    2900           0 :                         TALLOC_FREE(frame);
    2901           0 :                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2902             :                 }
    2903             : 
    2904         114 :                 old_val = ldb_msg_find_ldb_val(tdo_msg, "trustAuthIncoming");
    2905         114 :                 if (old_val != NULL) {
    2906         114 :                         ndr_err = ndr_pull_struct_blob(old_val, frame, &old_blob,
    2907             :                                         (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
    2908         114 :                         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    2909           0 :                                 ldb_transaction_cancel(ldb);
    2910           0 :                                 DEBUG(1, ("samdb_set_password_sid: "
    2911             :                                           "failed(%s) to parse "
    2912             :                                           "trustAuthOutgoing sAMAccountName[%s] "
    2913             :                                           "DN[%s] TDO[%s], "
    2914             :                                           "returning INTERNAL_DB_CORRUPTION\n",
    2915             :                                           ndr_map_error2string(ndr_err),
    2916             :                                           account_name,
    2917             :                                           ldb_dn_get_linearized(user_msg->dn),
    2918             :                                           ldb_dn_get_linearized(tdo_msg->dn)));
    2919             : 
    2920           0 :                                 TALLOC_FREE(frame);
    2921           0 :                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    2922             :                         }
    2923             :                 }
    2924             : 
    2925         300 :                 for (i = old_blob.current.count; i > 0; i--) {
    2926         186 :                         struct AuthenticationInformation *a =
    2927         186 :                                 &old_blob.current.array[i - 1];
    2928             : 
    2929         186 :                         switch (a->AuthType) {
    2930           0 :                         case TRUST_AUTH_TYPE_NONE:
    2931           0 :                                 if (i == old_blob.current.count) {
    2932             :                                         /*
    2933             :                                          * remove TRUST_AUTH_TYPE_NONE at the
    2934             :                                          * end
    2935             :                                          */
    2936           0 :                                         old_blob.current.count--;
    2937             :                                 }
    2938           0 :                                 break;
    2939             : 
    2940          72 :                         case TRUST_AUTH_TYPE_VERSION:
    2941          72 :                                 old_version_a = a;
    2942          72 :                                 old_version = a->AuthInfo.version.version;
    2943          72 :                                 break;
    2944             : 
    2945         114 :                         case TRUST_AUTH_TYPE_CLEAR:
    2946         114 :                                 break;
    2947             : 
    2948           0 :                         case TRUST_AUTH_TYPE_NT4OWF:
    2949           0 :                                 break;
    2950             :                         }
    2951             :                 }
    2952             : 
    2953         114 :                 if (new_version == NULL) {
    2954           0 :                         _new_version = 0;
    2955           0 :                         new_version = &_new_version;
    2956             :                 }
    2957             : 
    2958         114 :                 if (old_version_a != NULL && *new_version != (old_version + 1)) {
    2959          36 :                         old_version_a->LastUpdateTime = now;
    2960          36 :                         old_version_a->AuthType = TRUST_AUTH_TYPE_NONE;
    2961             :                 }
    2962             : 
    2963         114 :                 new_blob.count = MAX(old_blob.current.count, 2);
    2964         114 :                 new_blob.current.array = talloc_zero_array(frame,
    2965             :                                                 struct AuthenticationInformation,
    2966             :                                                 new_blob.count);
    2967         114 :                 if (new_blob.current.array == NULL) {
    2968           0 :                         ldb_transaction_cancel(ldb);
    2969           0 :                         TALLOC_FREE(frame);
    2970           0 :                         return NT_STATUS_NO_MEMORY;
    2971             :                 }
    2972         114 :                 new_blob.previous.array = talloc_zero_array(frame,
    2973             :                                                 struct AuthenticationInformation,
    2974             :                                                 new_blob.count);
    2975         114 :                 if (new_blob.current.array == NULL) {
    2976           0 :                         ldb_transaction_cancel(ldb);
    2977           0 :                         TALLOC_FREE(frame);
    2978           0 :                         return NT_STATUS_NO_MEMORY;
    2979             :                 }
    2980             : 
    2981         300 :                 for (i = 0; i < old_blob.current.count; i++) {
    2982         186 :                         struct AuthenticationInformation *o =
    2983         186 :                                 &old_blob.current.array[i];
    2984         186 :                         struct AuthenticationInformation *p =
    2985         186 :                                 &new_blob.previous.array[i];
    2986             : 
    2987         186 :                         *p = *o;
    2988         186 :                         new_blob.previous.count++;
    2989             :                 }
    2990         156 :                 for (; i < new_blob.count; i++) {
    2991          42 :                         struct AuthenticationInformation *pi =
    2992          42 :                                 &new_blob.previous.array[i];
    2993             : 
    2994          42 :                         if (i == 0) {
    2995             :                                 /*
    2996             :                                  * new_blob.previous is still empty so
    2997             :                                  * we'll do new_blob.previous = new_blob.current
    2998             :                                  * below.
    2999             :                                  */
    3000           0 :                                 break;
    3001             :                         }
    3002             : 
    3003          42 :                         pi->LastUpdateTime = now;
    3004          42 :                         pi->AuthType = TRUST_AUTH_TYPE_NONE;
    3005          42 :                         new_blob.previous.count++;
    3006             :                 }
    3007             : 
    3008         342 :                 for (i = 0; i < new_blob.count; i++) {
    3009         228 :                         struct AuthenticationInformation *ci =
    3010         228 :                                 &new_blob.current.array[i];
    3011             : 
    3012         228 :                         ci->LastUpdateTime = now;
    3013         228 :                         switch (i) {
    3014         114 :                         case 0:
    3015         114 :                                 if (ntNewHash != NULL) {
    3016           0 :                                         ci->AuthType = TRUST_AUTH_TYPE_NT4OWF;
    3017           0 :                                         ci->AuthInfo.nt4owf.password = *ntNewHash;
    3018           0 :                                         break;
    3019             :                                 }
    3020             : 
    3021         114 :                                 ci->AuthType = TRUST_AUTH_TYPE_CLEAR;
    3022         114 :                                 ci->AuthInfo.clear.size = new_password->length;
    3023         114 :                                 ci->AuthInfo.clear.password = new_password->data;
    3024         114 :                                 break;
    3025         114 :                         case 1:
    3026         114 :                                 ci->AuthType = TRUST_AUTH_TYPE_VERSION;
    3027         114 :                                 ci->AuthInfo.version.version = *new_version;
    3028         114 :                                 break;
    3029           0 :                         default:
    3030           0 :                                 ci->AuthType = TRUST_AUTH_TYPE_NONE;
    3031           0 :                                 break;
    3032             :                         }
    3033             : 
    3034         228 :                         new_blob.current.count++;
    3035             :                 }
    3036             : 
    3037         114 :                 if (new_blob.previous.count == 0) {
    3038           0 :                         TALLOC_FREE(new_blob.previous.array);
    3039           0 :                         new_blob.previous = new_blob.current;
    3040             :                 }
    3041             : 
    3042         114 :                 ndr_err = ndr_push_struct_blob(&new_val, frame, &new_blob,
    3043             :                                 (ndr_push_flags_fn_t)ndr_push_trustAuthInOutBlob);
    3044         114 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    3045           0 :                         ldb_transaction_cancel(ldb);
    3046           0 :                         DEBUG(1, ("samdb_set_password_sid: "
    3047             :                                   "failed(%s) to generate "
    3048             :                                   "trustAuthOutgoing sAMAccountName[%s] "
    3049             :                                   "DN[%s] TDO[%s], "
    3050             :                                   "returning UNSUCCESSFUL\n",
    3051             :                                   ndr_map_error2string(ndr_err),
    3052             :                                   account_name,
    3053             :                                   ldb_dn_get_linearized(user_msg->dn),
    3054             :                                   ldb_dn_get_linearized(tdo_msg->dn)));
    3055           0 :                         TALLOC_FREE(frame);
    3056           0 :                         return NT_STATUS_UNSUCCESSFUL;
    3057             :                 }
    3058             : 
    3059         114 :                 tdo_msg->num_elements = 0;
    3060         114 :                 TALLOC_FREE(tdo_msg->elements);
    3061             : 
    3062         114 :                 ret = ldb_msg_append_value(tdo_msg, "trustAuthIncoming",
    3063             :                                            &new_val, LDB_FLAG_MOD_REPLACE);
    3064         114 :                 if (ret != LDB_SUCCESS) {
    3065           0 :                         ldb_transaction_cancel(ldb);
    3066           0 :                         TALLOC_FREE(frame);
    3067           0 :                         return NT_STATUS_NO_MEMORY;
    3068             :                 }
    3069             : 
    3070         114 :                 ret = ldb_modify(ldb, tdo_msg);
    3071         114 :                 if (ret != LDB_SUCCESS) {
    3072           0 :                         nt_status = dsdb_ldb_err_to_ntstatus(ret);
    3073           0 :                         ldb_transaction_cancel(ldb);
    3074           0 :                         DEBUG(1, ("samdb_set_password_sid: "
    3075             :                                   "failed to replace "
    3076             :                                   "trustAuthOutgoing sAMAccountName[%s] "
    3077             :                                   "DN[%s] TDO[%s], "
    3078             :                                   "%s - %s\n",
    3079             :                                   account_name,
    3080             :                                   ldb_dn_get_linearized(user_msg->dn),
    3081             :                                   ldb_dn_get_linearized(tdo_msg->dn),
    3082             :                                   nt_errstr(nt_status), ldb_errstring(ldb)));
    3083           0 :                         TALLOC_FREE(frame);
    3084           0 :                         return nt_status;
    3085             :                 }
    3086             :         }
    3087             : 
    3088         445 :         nt_status = samdb_set_password_internal(ldb, mem_ctx,
    3089         414 :                                                 user_msg->dn,
    3090             :                                                 new_password,
    3091             :                                                 ntNewHash,
    3092             :                                                 old_password_checked,
    3093             :                                                 reject_reason, _dominfo,
    3094             :                                                 true); /* permit trusts */
    3095         414 :         if (!NT_STATUS_IS_OK(nt_status)) {
    3096          10 :                 ldb_transaction_cancel(ldb);
    3097          10 :                 TALLOC_FREE(frame);
    3098          10 :                 return nt_status;
    3099             :         }
    3100             : 
    3101         404 :         ret = ldb_transaction_commit(ldb);
    3102         404 :         if (ret != LDB_SUCCESS) {
    3103           0 :                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
    3104             :                          ldb_dn_get_linearized(user_msg->dn),
    3105             :                          ldb_errstring(ldb)));
    3106           0 :                 TALLOC_FREE(frame);
    3107           0 :                 return NT_STATUS_TRANSACTION_ABORTED;
    3108             :         }
    3109             : 
    3110         404 :         TALLOC_FREE(frame);
    3111         404 :         return NT_STATUS_OK;
    3112             : }
    3113             : 
    3114             : 
    3115           0 : NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx,
    3116             :                                                  struct dom_sid *sid, struct ldb_dn **ret_dn)
    3117             : {
    3118           0 :         struct ldb_message *msg;
    3119           0 :         struct ldb_dn *basedn = NULL;
    3120           0 :         char *sidstr;
    3121           0 :         int ret;
    3122             : 
    3123           0 :         sidstr = dom_sid_string(mem_ctx, sid);
    3124           0 :         NT_STATUS_HAVE_NO_MEMORY(sidstr);
    3125             : 
    3126             :         /* We might have to create a ForeignSecurityPrincipal, even if this user
    3127             :          * is in our own domain */
    3128             : 
    3129           0 :         msg = ldb_msg_new(sidstr);
    3130           0 :         if (msg == NULL) {
    3131           0 :                 talloc_free(sidstr);
    3132           0 :                 return NT_STATUS_NO_MEMORY;
    3133             :         }
    3134             : 
    3135           0 :         ret = dsdb_wellknown_dn(sam_ctx, sidstr,
    3136             :                                 ldb_get_default_basedn(sam_ctx),
    3137             :                                 DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
    3138             :                                 &basedn);
    3139           0 :         if (ret != LDB_SUCCESS) {
    3140           0 :                 DEBUG(0, ("Failed to find DN for "
    3141             :                           "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
    3142           0 :                 talloc_free(sidstr);
    3143           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    3144             :         }
    3145             : 
    3146             :         /* add core elements to the ldb_message for the alias */
    3147           0 :         msg->dn = basedn;
    3148           0 :         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
    3149           0 :                 talloc_free(sidstr);
    3150           0 :                 return NT_STATUS_NO_MEMORY;
    3151             :         }
    3152             : 
    3153           0 :         ret = ldb_msg_add_string(msg, "objectClass",
    3154             :                                  "foreignSecurityPrincipal");
    3155           0 :         if (ret != LDB_SUCCESS) {
    3156           0 :                 talloc_free(sidstr);
    3157           0 :                 return NT_STATUS_NO_MEMORY;
    3158             :         }
    3159             : 
    3160             :         /* create the alias */
    3161           0 :         ret = ldb_add(sam_ctx, msg);
    3162           0 :         if (ret != LDB_SUCCESS) {
    3163           0 :                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
    3164             :                          "record %s: %s\n",
    3165             :                          ldb_dn_get_linearized(msg->dn),
    3166             :                          ldb_errstring(sam_ctx)));
    3167           0 :                 talloc_free(sidstr);
    3168           0 :                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    3169             :         }
    3170             : 
    3171           0 :         *ret_dn = talloc_steal(mem_ctx, msg->dn);
    3172           0 :         talloc_free(sidstr);
    3173             : 
    3174           0 :         return NT_STATUS_OK;
    3175             : }
    3176             : 
    3177             : 
    3178             : /*
    3179             :   Find the DN of a domain, assuming it to be a dotted.dns name
    3180             : */
    3181             : 
    3182           0 : struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
    3183             : {
    3184           0 :         unsigned int i;
    3185           0 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    3186           0 :         const char *binary_encoded;
    3187           0 :         const char * const *split_realm;
    3188           0 :         struct ldb_dn *dn;
    3189             : 
    3190           0 :         if (!tmp_ctx) {
    3191           0 :                 return NULL;
    3192             :         }
    3193             : 
    3194           0 :         split_realm = (const char * const *)str_list_make(tmp_ctx, dns_domain, ".");
    3195           0 :         if (!split_realm) {
    3196           0 :                 talloc_free(tmp_ctx);
    3197           0 :                 return NULL;
    3198             :         }
    3199           0 :         dn = ldb_dn_new(mem_ctx, ldb, NULL);
    3200           0 :         for (i=0; split_realm[i]; i++) {
    3201           0 :                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
    3202           0 :                 if (binary_encoded == NULL) {
    3203           0 :                         DEBUG(2, ("Failed to add dc= element to DN %s\n",
    3204             :                                   ldb_dn_get_linearized(dn)));
    3205           0 :                         talloc_free(tmp_ctx);
    3206           0 :                         return NULL;
    3207             :                 }
    3208           0 :                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
    3209           0 :                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
    3210             :                                   binary_encoded, ldb_dn_get_linearized(dn)));
    3211           0 :                         talloc_free(tmp_ctx);
    3212           0 :                         return NULL;
    3213             :                 }
    3214             :         }
    3215           0 :         if (!ldb_dn_validate(dn)) {
    3216           0 :                 DEBUG(2, ("Failed to validated DN %s\n",
    3217             :                           ldb_dn_get_linearized(dn)));
    3218           0 :                 talloc_free(tmp_ctx);
    3219           0 :                 return NULL;
    3220             :         }
    3221           0 :         talloc_free(tmp_ctx);
    3222           0 :         return dn;
    3223             : }
    3224             : 
    3225             : 
    3226             : /*
    3227             :   Find the DNS equivalent of a DN, in dotted DNS form
    3228             : */
    3229       51322 : char *samdb_dn_to_dns_domain(TALLOC_CTX *mem_ctx, struct ldb_dn *dn)
    3230             : {
    3231       51322 :         int i, num_components = ldb_dn_get_comp_num(dn);
    3232       51322 :         char *dns_name = talloc_strdup(mem_ctx, "");
    3233       51322 :         if (dns_name == NULL) {
    3234           0 :                 return NULL;
    3235             :         }
    3236             : 
    3237      231024 :         for (i=0; i<num_components; i++) {
    3238      179702 :                 const struct ldb_val *v = ldb_dn_get_component_val(dn, i);
    3239        3443 :                 char *s;
    3240      179702 :                 if (v == NULL) {
    3241           0 :                         talloc_free(dns_name);
    3242           0 :                         return NULL;
    3243             :                 }
    3244      183145 :                 s = talloc_asprintf_append_buffer(dns_name, "%*.*s.",
    3245      179702 :                                                   (int)v->length, (int)v->length, (char *)v->data);
    3246      179702 :                 if (s == NULL) {
    3247           0 :                         talloc_free(dns_name);
    3248           0 :                         return NULL;
    3249             :                 }
    3250      179702 :                 dns_name = s;
    3251             :         }
    3252             : 
    3253             :         /* remove the last '.' */
    3254       51322 :         if (dns_name[0] != 0) {
    3255       51322 :                 dns_name[strlen(dns_name)-1] = 0;
    3256             :         }
    3257             : 
    3258       50238 :         return dns_name;
    3259             : }
    3260             : 
    3261             : /*
    3262             :   Find the DNS _msdcs name for a given NTDS GUID. The resulting DNS
    3263             :   name is based on the forest DNS name
    3264             : */
    3265        4635 : char *samdb_ntds_msdcs_dns_name(struct ldb_context *samdb,
    3266             :                                 TALLOC_CTX *mem_ctx,
    3267             :                                 const struct GUID *ntds_guid)
    3268             : {
    3269        4635 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    3270           0 :         const char *guid_str;
    3271           0 :         struct ldb_dn *forest_dn;
    3272           0 :         const char *dnsforest;
    3273           0 :         char *ret;
    3274             : 
    3275        4635 :         guid_str = GUID_string(tmp_ctx, ntds_guid);
    3276        4635 :         if (guid_str == NULL) {
    3277           0 :                 talloc_free(tmp_ctx);
    3278           0 :                 return NULL;
    3279             :         }
    3280        4635 :         forest_dn = ldb_get_root_basedn(samdb);
    3281        4635 :         if (forest_dn == NULL) {
    3282           0 :                 talloc_free(tmp_ctx);
    3283           0 :                 return NULL;
    3284             :         }
    3285        4635 :         dnsforest = samdb_dn_to_dns_domain(tmp_ctx, forest_dn);
    3286        4635 :         if (dnsforest == NULL) {
    3287           0 :                 talloc_free(tmp_ctx);
    3288           0 :                 return NULL;
    3289             :         }
    3290        4635 :         ret = talloc_asprintf(mem_ctx, "%s._msdcs.%s", guid_str, dnsforest);
    3291        4635 :         talloc_free(tmp_ctx);
    3292        4635 :         return ret;
    3293             : }
    3294             : 
    3295             : 
    3296             : /*
    3297             :   Find the DN of a domain, be it the netbios or DNS name
    3298             : */
    3299          22 : struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    3300             :                                   const char *domain_name)
    3301             : {
    3302          22 :         const char * const domain_ref_attrs[] = {
    3303             :                 "ncName", NULL
    3304             :         };
    3305          22 :         const char * const domain_ref2_attrs[] = {
    3306             :                 NULL
    3307             :         };
    3308           3 :         struct ldb_result *res_domain_ref;
    3309          22 :         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
    3310           3 :         int ret_domain;
    3311             : 
    3312          22 :         if (escaped_domain == NULL) {
    3313           0 :                 return NULL;
    3314             :         }
    3315             : 
    3316             :         /* find the domain's DN */
    3317          22 :         ret_domain = ldb_search(ldb, mem_ctx,
    3318             :                                 &res_domain_ref,
    3319             :                                 samdb_partitions_dn(ldb, mem_ctx),
    3320             :                                 LDB_SCOPE_ONELEVEL,
    3321             :                                 domain_ref_attrs,
    3322             :                                 "(&(nETBIOSName=%s)(objectclass=crossRef))",
    3323             :                                 escaped_domain);
    3324          22 :         if (ret_domain != LDB_SUCCESS) {
    3325           0 :                 return NULL;
    3326             :         }
    3327             : 
    3328          22 :         if (res_domain_ref->count == 0) {
    3329           0 :                 ret_domain = ldb_search(ldb, mem_ctx,
    3330             :                                                 &res_domain_ref,
    3331             :                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
    3332             :                                                 LDB_SCOPE_BASE,
    3333             :                                                 domain_ref2_attrs,
    3334             :                                                 "(objectclass=domain)");
    3335           0 :                 if (ret_domain != LDB_SUCCESS) {
    3336           0 :                         return NULL;
    3337             :                 }
    3338             : 
    3339           0 :                 if (res_domain_ref->count == 1) {
    3340           0 :                         return res_domain_ref->msgs[0]->dn;
    3341             :                 }
    3342           0 :                 return NULL;
    3343             :         }
    3344             : 
    3345          22 :         if (res_domain_ref->count > 1) {
    3346           0 :                 DEBUG(0,("Found %d records matching domain [%s]\n",
    3347             :                          ret_domain, domain_name));
    3348           0 :                 return NULL;
    3349             :         }
    3350             : 
    3351          22 :         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
    3352             : 
    3353             : }
    3354             : 
    3355             : 
    3356             : /*
    3357             :   use a GUID to find a DN
    3358             :  */
    3359         668 : int dsdb_find_dn_by_guid(struct ldb_context *ldb,
    3360             :                          TALLOC_CTX *mem_ctx,
    3361             :                          const struct GUID *guid,
    3362             :                          uint32_t dsdb_flags,
    3363             :                          struct ldb_dn **dn)
    3364             : {
    3365           0 :         int ret;
    3366           0 :         struct ldb_result *res;
    3367         668 :         const char *attrs[] = { NULL };
    3368           0 :         struct GUID_txt_buf buf;
    3369         668 :         char *guid_str = GUID_buf_string(guid, &buf);
    3370             : 
    3371         668 :         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
    3372             :                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
    3373             :                           DSDB_SEARCH_SHOW_EXTENDED_DN |
    3374             :                           DSDB_SEARCH_ONE_ONLY | dsdb_flags,
    3375             :                           "objectGUID=%s", guid_str);
    3376         668 :         if (ret != LDB_SUCCESS) {
    3377          67 :                 return ret;
    3378             :         }
    3379             : 
    3380         601 :         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
    3381         601 :         talloc_free(res);
    3382             : 
    3383         601 :         return LDB_SUCCESS;
    3384             : }
    3385             : 
    3386             : /*
    3387             :   use a DN to find a GUID with a given attribute name
    3388             :  */
    3389        3841 : int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
    3390             :                               struct ldb_dn *dn, const char *attribute,
    3391             :                               struct GUID *guid)
    3392             : {
    3393           0 :         int ret;
    3394        3841 :         struct ldb_result *res = NULL;
    3395           0 :         const char *attrs[2];
    3396        3841 :         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    3397             : 
    3398        3841 :         attrs[0] = attribute;
    3399        3841 :         attrs[1] = NULL;
    3400             : 
    3401        3841 :         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
    3402             :                              DSDB_SEARCH_SHOW_DELETED |
    3403             :                              DSDB_SEARCH_SHOW_RECYCLED);
    3404        3841 :         if (ret != LDB_SUCCESS) {
    3405           0 :                 talloc_free(tmp_ctx);
    3406           0 :                 return ret;
    3407             :         }
    3408             :         /* satisfy clang */
    3409        3841 :         if (res == NULL) {
    3410           0 :                 talloc_free(tmp_ctx);
    3411           0 :                 return LDB_ERR_OTHER;
    3412             :         }
    3413        3841 :         if (res->count < 1) {
    3414           0 :                 talloc_free(tmp_ctx);
    3415           0 :                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
    3416             :         }
    3417        3841 :         *guid = samdb_result_guid(res->msgs[0], attribute);
    3418        3841 :         talloc_free(tmp_ctx);
    3419        3841 :         return LDB_SUCCESS;
    3420             : }
    3421             : 
    3422             : /*
    3423             :   use a DN to find a GUID
    3424             :  */
    3425        3841 : int dsdb_find_guid_by_dn(struct ldb_context *ldb,
    3426             :                          struct ldb_dn *dn, struct GUID *guid)
    3427             : {
    3428        3841 :         return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
    3429             : }
    3430             : 
    3431             : 
    3432             : 
    3433             : /*
    3434             :  adds the given GUID to the given ldb_message. This value is added
    3435             :  for the given attr_name (may be either "objectGUID" or "parentGUID").
    3436             :  This function is used in processing 'add' requests.
    3437             :  */
    3438      926040 : int dsdb_msg_add_guid(struct ldb_message *msg,
    3439             :                 struct GUID *guid,
    3440             :                 const char *attr_name)
    3441             : {
    3442       83703 :         int ret;
    3443       83703 :         struct ldb_val v;
    3444       83703 :         NTSTATUS status;
    3445      926040 :         TALLOC_CTX *tmp_ctx =  talloc_init("dsdb_msg_add_guid");
    3446             : 
    3447      926040 :         status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
    3448      926040 :         if (!NT_STATUS_IS_OK(status)) {
    3449           0 :                 ret = LDB_ERR_OPERATIONS_ERROR;
    3450           0 :                 goto done;
    3451             :         }
    3452             : 
    3453      926040 :         ret = ldb_msg_add_steal_value(msg, attr_name, &v);
    3454      926040 :         if (ret != LDB_SUCCESS) {
    3455           0 :                 DEBUG(4,(__location__ ": Failed to add %s to the message\n",
    3456             :                                          attr_name));
    3457           0 :                 goto done;
    3458             :         }
    3459             : 
    3460      842337 :         ret = LDB_SUCCESS;
    3461             : 
    3462      926040 : done:
    3463      926040 :         talloc_free(tmp_ctx);
    3464      926040 :         return ret;
    3465             : 
    3466             : }
    3467             : 
    3468             : 
    3469             : /*
    3470             :   use a DN to find a SID
    3471             :  */
    3472        8182 : int dsdb_find_sid_by_dn(struct ldb_context *ldb,
    3473             :                         struct ldb_dn *dn, struct dom_sid *sid)
    3474             : {
    3475           0 :         int ret;
    3476        8182 :         struct ldb_result *res = NULL;
    3477        8182 :         const char *attrs[] = { "objectSid", NULL };
    3478        8182 :         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    3479           0 :         struct dom_sid *s;
    3480             : 
    3481        8182 :         ZERO_STRUCTP(sid);
    3482             : 
    3483        8182 :         ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
    3484             :                              DSDB_SEARCH_SHOW_DELETED |
    3485             :                              DSDB_SEARCH_SHOW_RECYCLED);
    3486        8182 :         if (ret != LDB_SUCCESS) {
    3487           0 :                 talloc_free(tmp_ctx);
    3488           0 :                 return ret;
    3489             :         }
    3490        8182 :         if (res == NULL) {
    3491           0 :                 talloc_free(tmp_ctx);
    3492           0 :                 return LDB_ERR_OTHER;
    3493             :         }
    3494        8182 :         if (res->count < 1) {
    3495           0 :                 talloc_free(tmp_ctx);
    3496           0 :                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
    3497             :         }
    3498        8182 :         s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
    3499        8182 :         if (s == NULL) {
    3500        1927 :                 talloc_free(tmp_ctx);
    3501        1927 :                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
    3502             :         }
    3503        6255 :         *sid = *s;
    3504        6255 :         talloc_free(tmp_ctx);
    3505        6255 :         return LDB_SUCCESS;
    3506             : }
    3507             : 
    3508             : /*
    3509             :   use a SID to find a DN
    3510             :  */
    3511          60 : int dsdb_find_dn_by_sid(struct ldb_context *ldb,
    3512             :                         TALLOC_CTX *mem_ctx,
    3513             :                         struct dom_sid *sid, struct ldb_dn **dn)
    3514             : {
    3515           0 :         int ret;
    3516           0 :         struct ldb_result *res;
    3517          60 :         const char *attrs[] = { NULL };
    3518          60 :         char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
    3519             : 
    3520          60 :         if (!sid_str) {
    3521           0 :                 return ldb_operr(ldb);
    3522             :         }
    3523             : 
    3524          60 :         ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
    3525             :                           DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
    3526             :                           DSDB_SEARCH_SHOW_EXTENDED_DN |
    3527             :                           DSDB_SEARCH_ONE_ONLY,
    3528             :                           "objectSid=%s", sid_str);
    3529          60 :         talloc_free(sid_str);
    3530          60 :         if (ret != LDB_SUCCESS) {
    3531           0 :                 return ret;
    3532             :         }
    3533             : 
    3534          60 :         *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
    3535          60 :         talloc_free(res);
    3536             : 
    3537          60 :         return LDB_SUCCESS;
    3538             : }
    3539             : 
    3540             : /*
    3541             :   load a repsFromTo blob list for a given partition GUID
    3542             :   attr must be "repsFrom" or "repsTo"
    3543             :  */
    3544       73649 : WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
    3545             :                      const char *attr, struct repsFromToBlob **r, uint32_t *count)
    3546             : {
    3547       73649 :         const char *attrs[] = { attr, NULL };
    3548       73649 :         struct ldb_result *res = NULL;
    3549       73649 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    3550         490 :         unsigned int i;
    3551         490 :         struct ldb_message_element *el;
    3552         490 :         int ret;
    3553             : 
    3554       73649 :         *r = NULL;
    3555       73649 :         *count = 0;
    3556             : 
    3557       73649 :         if (tmp_ctx == NULL) {
    3558           0 :                 return WERR_NOT_ENOUGH_MEMORY;
    3559             :         }
    3560             : 
    3561       73649 :         ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, dn, attrs, 0);
    3562       73649 :         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    3563             :                 /* partition hasn't been replicated yet */
    3564           0 :                 talloc_free(tmp_ctx);
    3565           0 :                 return WERR_OK;
    3566             :         }
    3567       73649 :         if (ret != LDB_SUCCESS) {
    3568           0 :                 DEBUG(0,("dsdb_loadreps: failed to read partition object: %s\n", ldb_errstring(sam_ctx)));
    3569           0 :                 talloc_free(tmp_ctx);
    3570           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    3571             :         }
    3572             : 
    3573             :         /* satisfy clang */
    3574       73649 :         if (res == NULL) {
    3575           0 :                 talloc_free(tmp_ctx);
    3576           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    3577             :         }
    3578       73649 :         el = ldb_msg_find_element(res->msgs[0], attr);
    3579       73649 :         if (el == NULL) {
    3580             :                 /* it's OK to be empty */
    3581       48259 :                 talloc_free(tmp_ctx);
    3582       48259 :                 return WERR_OK;
    3583             :         }
    3584             : 
    3585       25390 :         *count = el->num_values;
    3586       25390 :         *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
    3587       25390 :         if (*r == NULL) {
    3588           0 :                 talloc_free(tmp_ctx);
    3589           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    3590             :         }
    3591             : 
    3592       68644 :         for (i=0; i<(*count); i++) {
    3593           0 :                 enum ndr_err_code ndr_err;
    3594       43254 :                 ndr_err = ndr_pull_struct_blob(&el->values[i],
    3595             :                                                mem_ctx,
    3596       43254 :                                                &(*r)[i],
    3597             :                                                (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
    3598       43254 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    3599           0 :                         talloc_free(tmp_ctx);
    3600           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    3601             :                 }
    3602             :         }
    3603             : 
    3604       25390 :         talloc_free(tmp_ctx);
    3605             : 
    3606       25390 :         return WERR_OK;
    3607             : }
    3608             : 
    3609             : /*
    3610             :   save the repsFromTo blob list for a given partition GUID
    3611             :   attr must be "repsFrom" or "repsTo"
    3612             :  */
    3613       11965 : WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
    3614             :                      const char *attr, struct repsFromToBlob *r, uint32_t count)
    3615             : {
    3616       11965 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    3617           0 :         struct ldb_message *msg;
    3618           0 :         struct ldb_message_element *el;
    3619           0 :         unsigned int i;
    3620             : 
    3621       11965 :         if (tmp_ctx == NULL) {
    3622           0 :                 goto failed;
    3623             :         }
    3624             : 
    3625       11965 :         msg = ldb_msg_new(tmp_ctx);
    3626       11965 :         if (msg == NULL) {
    3627           0 :                 goto failed;
    3628             :         }
    3629       11965 :         msg->dn = dn;
    3630       11965 :         if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
    3631           0 :                 goto failed;
    3632             :         }
    3633             : 
    3634       11965 :         el->values = talloc_array(msg, struct ldb_val, count);
    3635       11965 :         if (!el->values) {
    3636           0 :                 goto failed;
    3637             :         }
    3638             : 
    3639       34747 :         for (i=0; i<count; i++) {
    3640           0 :                 struct ldb_val v;
    3641           0 :                 enum ndr_err_code ndr_err;
    3642             : 
    3643       22782 :                 ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
    3644       22782 :                                                &r[i],
    3645             :                                                (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
    3646       22782 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    3647           0 :                         goto failed;
    3648             :                 }
    3649             : 
    3650       22782 :                 el->num_values++;
    3651       22782 :                 el->values[i] = v;
    3652             :         }
    3653             : 
    3654       11965 :         if (dsdb_modify(sam_ctx, msg, 0) != LDB_SUCCESS) {
    3655           0 :                 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
    3656           0 :                 goto failed;
    3657             :         }
    3658             : 
    3659       11965 :         talloc_free(tmp_ctx);
    3660             : 
    3661       11965 :         return WERR_OK;
    3662             : 
    3663           0 : failed:
    3664           0 :         talloc_free(tmp_ctx);
    3665           0 :         return WERR_DS_DRA_INTERNAL_ERROR;
    3666             : }
    3667             : 
    3668             : 
    3669             : /*
    3670             :   load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
    3671             :   object for a partition
    3672             :  */
    3673       63355 : int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
    3674             :                                 uint64_t *uSN, uint64_t *urgent_uSN)
    3675             : {
    3676         490 :         struct ldb_request *req;
    3677         490 :         int ret;
    3678       63355 :         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    3679         490 :         struct dsdb_control_current_partition *p_ctrl;
    3680         490 :         struct ldb_result *res;
    3681             : 
    3682       63355 :         if (tmp_ctx == NULL) {
    3683           0 :                 return ldb_oom(ldb);
    3684             :         }
    3685             : 
    3686       63355 :         res = talloc_zero(tmp_ctx, struct ldb_result);
    3687       63355 :         if (!res) {
    3688           0 :                 talloc_free(tmp_ctx);
    3689           0 :                 return ldb_oom(ldb);
    3690             :         }
    3691             : 
    3692       63355 :         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
    3693             :                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
    3694             :                                    LDB_SCOPE_BASE,
    3695             :                                    NULL, NULL,
    3696             :                                    NULL,
    3697             :                                    res, ldb_search_default_callback,
    3698             :                                    NULL);
    3699       63355 :         if (ret != LDB_SUCCESS) {
    3700           0 :                 talloc_free(tmp_ctx);
    3701           0 :                 return ret;
    3702             :         }
    3703             : 
    3704       63355 :         p_ctrl = talloc(req, struct dsdb_control_current_partition);
    3705       63355 :         if (p_ctrl == NULL) {
    3706           0 :                 talloc_free(tmp_ctx);
    3707           0 :                 return ldb_oom(ldb);
    3708             :         }
    3709       63355 :         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
    3710       63355 :         p_ctrl->dn = dn;
    3711             : 
    3712       63355 :         ret = ldb_request_add_control(req,
    3713             :                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
    3714             :                                       false, p_ctrl);
    3715       63355 :         if (ret != LDB_SUCCESS) {
    3716           0 :                 talloc_free(tmp_ctx);
    3717           0 :                 return ret;
    3718             :         }
    3719             : 
    3720             :         /* Run the new request */
    3721       63355 :         ret = ldb_request(ldb, req);
    3722             : 
    3723       63355 :         if (ret == LDB_SUCCESS) {
    3724       63355 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    3725             :         }
    3726             : 
    3727       63355 :         if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
    3728             :                 /* it hasn't been created yet, which means
    3729             :                    an implicit value of zero */
    3730        2558 :                 *uSN = 0;
    3731        2558 :                 talloc_free(tmp_ctx);
    3732        2558 :                 return LDB_SUCCESS;
    3733             :         }
    3734             : 
    3735       60797 :         if (ret != LDB_SUCCESS) {
    3736           0 :                 talloc_free(tmp_ctx);
    3737           0 :                 return ret;
    3738             :         }
    3739             : 
    3740       60797 :         if (res->count < 1) {
    3741           0 :                 *uSN = 0;
    3742           0 :                 if (urgent_uSN) {
    3743           0 :                         *urgent_uSN = 0;
    3744             :                 }
    3745             :         } else {
    3746       60797 :                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
    3747       60797 :                 if (urgent_uSN) {
    3748       55567 :                         *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
    3749             :                 }
    3750             :         }
    3751             : 
    3752       60797 :         talloc_free(tmp_ctx);
    3753             : 
    3754       60797 :         return LDB_SUCCESS;
    3755             : }
    3756             : 
    3757       15494 : int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
    3758             :                                                    const struct drsuapi_DsReplicaCursor2 *c2)
    3759             : {
    3760       15494 :         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
    3761             : }
    3762             : 
    3763        2823 : int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
    3764             :                                     const struct drsuapi_DsReplicaCursor *c2)
    3765             : {
    3766        2823 :         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
    3767             : }
    3768             : 
    3769             : /*
    3770             :  * Return the NTDS object for a GUID, confirming it is in the
    3771             :  * configuration partition and a nTDSDSA object
    3772             :  */
    3773       44973 : int samdb_get_ntds_obj_by_guid(TALLOC_CTX *mem_ctx,
    3774             :                                struct ldb_context *sam_ctx,
    3775             :                                const struct GUID *objectGUID,
    3776             :                                const char **attrs,
    3777             :                                struct ldb_message **msg)
    3778             : {
    3779        1143 :         int ret;
    3780        1143 :         struct ldb_result *res;
    3781        1143 :         struct GUID_txt_buf guid_buf;
    3782       44973 :         char *guid_str = GUID_buf_string(objectGUID, &guid_buf);
    3783       44973 :         struct ldb_dn *config_dn = NULL;
    3784             : 
    3785       44973 :         config_dn = ldb_get_config_basedn(sam_ctx);
    3786       44973 :         if (config_dn == NULL) {
    3787           0 :                 return ldb_operr(sam_ctx);
    3788             :         }
    3789             : 
    3790       44973 :         ret = dsdb_search(sam_ctx,
    3791             :                           mem_ctx,
    3792             :                           &res,
    3793             :                           config_dn,
    3794             :                           LDB_SCOPE_SUBTREE,
    3795             :                           attrs,
    3796             :                           DSDB_SEARCH_ONE_ONLY,
    3797             :                           "(&(objectGUID=%s)(objectClass=nTDSDSA))",
    3798             :                           guid_str);
    3799       44973 :         if (ret != LDB_SUCCESS) {
    3800          24 :                 return ret;
    3801             :         }
    3802       44949 :         if (msg) {
    3803       44883 :                 *msg = talloc_steal(mem_ctx, res->msgs[0]);
    3804             :         }
    3805       44949 :         TALLOC_FREE(res);
    3806       43806 :         return ret;
    3807             : }
    3808             : 
    3809             : 
    3810             : /*
    3811             :   see if a computer identified by its objectGUID is a RODC
    3812             : */
    3813       40503 : int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
    3814             : {
    3815             :         /* 1) find the DN for this servers NTDSDSA object
    3816             :            2) search for the msDS-isRODC attribute
    3817             :            3) if not present then not a RODC
    3818             :            4) if present and TRUE then is a RODC
    3819             :         */
    3820       40503 :         const char *attrs[] = { "msDS-isRODC", NULL };
    3821        1143 :         int ret;
    3822        1143 :         struct ldb_message *msg;
    3823       40503 :         TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
    3824             : 
    3825       40503 :         if (tmp_ctx == NULL) {
    3826           0 :                 return ldb_oom(sam_ctx);
    3827             :         }
    3828             : 
    3829       40503 :         ret = samdb_get_ntds_obj_by_guid(tmp_ctx,
    3830             :                                          sam_ctx,
    3831             :                                          objectGUID,
    3832             :                                          attrs, &msg);
    3833             : 
    3834       40503 :         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    3835           2 :                 *is_rodc = false;
    3836           2 :                 talloc_free(tmp_ctx);
    3837           2 :                 return LDB_SUCCESS;
    3838             :         }
    3839             : 
    3840       40501 :         if (ret != LDB_SUCCESS) {
    3841           0 :                 DEBUG(1,("Failed to find our own NTDS Settings object by objectGUID=%s!\n",
    3842             :                          GUID_string(tmp_ctx, objectGUID)));
    3843           0 :                 *is_rodc = false;
    3844           0 :                 talloc_free(tmp_ctx);
    3845           0 :                 return ret;
    3846             :         }
    3847             : 
    3848       40501 :         ret = ldb_msg_find_attr_as_bool(msg, "msDS-isRODC", 0);
    3849       40501 :         *is_rodc = (ret == 1);
    3850             : 
    3851       40501 :         talloc_free(tmp_ctx);
    3852       40501 :         return LDB_SUCCESS;
    3853             : }
    3854             : 
    3855             : 
    3856             : /*
    3857             :   see if we are a RODC
    3858             : */
    3859     1831457 : int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
    3860             : {
    3861      166886 :         const struct GUID *objectGUID;
    3862      166886 :         int ret;
    3863      166886 :         bool *cached;
    3864             : 
    3865             :         /* see if we have a cached copy */
    3866     1831457 :         cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
    3867     1831457 :         if (cached) {
    3868     1790937 :                 *am_rodc = *cached;
    3869     1790937 :                 return LDB_SUCCESS;
    3870             :         }
    3871             : 
    3872       40520 :         objectGUID = samdb_ntds_objectGUID(sam_ctx);
    3873       40520 :         if (!objectGUID) {
    3874          19 :                 return ldb_operr(sam_ctx);
    3875             :         }
    3876             : 
    3877       40501 :         ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
    3878       40501 :         if (ret != LDB_SUCCESS) {
    3879           0 :                 return ret;
    3880             :         }
    3881             : 
    3882       40501 :         cached = talloc(sam_ctx, bool);
    3883       40501 :         if (cached == NULL) {
    3884           0 :                 return ldb_oom(sam_ctx);
    3885             :         }
    3886       40501 :         *cached = *am_rodc;
    3887             : 
    3888       40501 :         ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
    3889       40501 :         if (ret != LDB_SUCCESS) {
    3890           0 :                 talloc_free(cached);
    3891           0 :                 return ldb_operr(sam_ctx);
    3892             :         }
    3893             : 
    3894       39358 :         return LDB_SUCCESS;
    3895             : }
    3896             : 
    3897        3022 : int samdb_dns_host_name(struct ldb_context *sam_ctx, const char **host_name)
    3898             : {
    3899        3022 :         const char *_host_name = NULL;
    3900        3022 :         const char *attrs[] = { "dnsHostName", NULL };
    3901        3022 :         TALLOC_CTX *tmp_ctx = NULL;
    3902           1 :         int ret;
    3903        3022 :         struct ldb_result *res = NULL;
    3904             : 
    3905        3022 :         _host_name = (const char *)ldb_get_opaque(sam_ctx, "cache.dns_host_name");
    3906        3022 :         if (_host_name != NULL) {
    3907        2895 :                 *host_name = _host_name;
    3908        2895 :                 return LDB_SUCCESS;
    3909             :         }
    3910             : 
    3911         127 :         tmp_ctx = talloc_new(sam_ctx);
    3912         127 :         if (tmp_ctx == NULL) {
    3913           0 :                 return ldb_oom(sam_ctx);
    3914             :         }
    3915             : 
    3916         127 :         ret = dsdb_search_dn(sam_ctx, tmp_ctx, &res, NULL, attrs, 0);
    3917             : 
    3918         127 :         if (res == NULL || res->count != 1 || ret != LDB_SUCCESS) {
    3919           0 :                 DEBUG(0, ("Failed to get rootDSE for dnsHostName: %s\n",
    3920             :                           ldb_errstring(sam_ctx)));
    3921           0 :                 TALLOC_FREE(tmp_ctx);
    3922           0 :                 return ret;
    3923             :         }
    3924             : 
    3925         127 :         _host_name = ldb_msg_find_attr_as_string(res->msgs[0],
    3926             :                                                  "dnsHostName",
    3927             :                                                  NULL);
    3928         127 :         if (_host_name == NULL) {
    3929           0 :                 DEBUG(0, ("Failed to get dnsHostName from rootDSE\n"));
    3930           0 :                 TALLOC_FREE(tmp_ctx);
    3931           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    3932             :         }
    3933         127 :         ret = ldb_set_opaque(sam_ctx, "cache.dns_host_name",
    3934             :                              discard_const_p(char *, _host_name));
    3935         127 :         if (ret != LDB_SUCCESS) {
    3936           0 :                 TALLOC_FREE(tmp_ctx);
    3937           0 :                 return ldb_operr(sam_ctx);
    3938             :         }
    3939             : 
    3940         127 :         *host_name = talloc_steal(sam_ctx, _host_name);
    3941             : 
    3942         127 :         TALLOC_FREE(tmp_ctx);
    3943         127 :         return LDB_SUCCESS;
    3944             : }
    3945             : 
    3946         692 : bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
    3947             : {
    3948          47 :         TALLOC_CTX *tmp_ctx;
    3949          47 :         bool *cached;
    3950             : 
    3951         692 :         tmp_ctx = talloc_new(ldb);
    3952         692 :         if (tmp_ctx == NULL) {
    3953           0 :                 goto failed;
    3954             :         }
    3955             : 
    3956         692 :         cached = talloc(tmp_ctx, bool);
    3957         692 :         if (!cached) {
    3958           0 :                 goto failed;
    3959             :         }
    3960             : 
    3961         692 :         *cached = am_rodc;
    3962         692 :         if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
    3963           0 :                 goto failed;
    3964             :         }
    3965             : 
    3966         692 :         talloc_steal(ldb, cached);
    3967         692 :         talloc_free(tmp_ctx);
    3968         692 :         return true;
    3969             : 
    3970           0 : failed:
    3971           0 :         DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
    3972           0 :         talloc_free(tmp_ctx);
    3973           0 :         return false;
    3974             : }
    3975             : 
    3976             : 
    3977             : /*
    3978             :  * return NTDSSiteSettings options. See MS-ADTS 7.1.1.2.2.1.1
    3979             :  * flags are DS_NTDSSETTINGS_OPT_*
    3980             :  */
    3981           0 : int samdb_ntds_site_settings_options(struct ldb_context *ldb_ctx,
    3982             :                                         uint32_t *options)
    3983             : {
    3984           0 :         int rc;
    3985           0 :         TALLOC_CTX *tmp_ctx;
    3986           0 :         struct ldb_result *res;
    3987           0 :         struct ldb_dn *site_dn;
    3988           0 :         const char *attrs[] = { "options", NULL };
    3989             : 
    3990           0 :         tmp_ctx = talloc_new(ldb_ctx);
    3991           0 :         if (tmp_ctx == NULL)
    3992           0 :                 goto failed;
    3993             : 
    3994             :         /* Retrieve the site dn for the ldb that we
    3995             :          * have open.  This is our local site.
    3996             :          */
    3997           0 :         site_dn = samdb_server_site_dn(ldb_ctx, tmp_ctx);
    3998           0 :         if (site_dn == NULL)
    3999           0 :                 goto failed;
    4000             : 
    4001             :         /* Perform a one level (child) search from the local
    4002             :          * site distinguished name.   We're looking for the
    4003             :          * "options" attribute within the nTDSSiteSettings
    4004             :          * object
    4005             :          */
    4006           0 :         rc = ldb_search(ldb_ctx, tmp_ctx, &res, site_dn,
    4007             :                         LDB_SCOPE_ONELEVEL, attrs,
    4008             :                         "objectClass=nTDSSiteSettings");
    4009             : 
    4010           0 :         if (rc != LDB_SUCCESS || res->count != 1)
    4011           0 :                 goto failed;
    4012             : 
    4013           0 :         *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
    4014             : 
    4015           0 :         talloc_free(tmp_ctx);
    4016             : 
    4017           0 :         return LDB_SUCCESS;
    4018             : 
    4019           0 : failed:
    4020           0 :         DEBUG(1,("Failed to find our NTDS Site Settings options in ldb!\n"));
    4021           0 :         talloc_free(tmp_ctx);
    4022           0 :         return ldb_error(ldb_ctx, LDB_ERR_NO_SUCH_OBJECT, __func__);
    4023             : }
    4024             : 
    4025             : /*
    4026             :   return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
    4027             : 
    4028             :   flags are DS_NTDS_OPTION_*
    4029             : */
    4030       17909 : int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
    4031             : {
    4032          72 :         TALLOC_CTX *tmp_ctx;
    4033       17909 :         const char *attrs[] = { "options", NULL };
    4034          72 :         int ret;
    4035          72 :         struct ldb_result *res;
    4036             : 
    4037       17909 :         tmp_ctx = talloc_new(ldb);
    4038       17909 :         if (tmp_ctx == NULL) {
    4039           0 :                 goto failed;
    4040             :         }
    4041             : 
    4042       17909 :         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
    4043       17909 :         if (ret != LDB_SUCCESS) {
    4044           0 :                 goto failed;
    4045             :         }
    4046             : 
    4047       17909 :         if (res->count != 1) {
    4048           0 :                 goto failed;
    4049             :         }
    4050             : 
    4051       17909 :         *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
    4052             : 
    4053       17909 :         talloc_free(tmp_ctx);
    4054             : 
    4055       17909 :         return LDB_SUCCESS;
    4056             : 
    4057           0 : failed:
    4058           0 :         DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
    4059           0 :         talloc_free(tmp_ctx);
    4060           0 :         return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
    4061             : }
    4062             : 
    4063           0 : const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
    4064             : {
    4065           0 :         const char *attrs[] = { "objectCategory", NULL };
    4066           0 :         int ret;
    4067           0 :         struct ldb_result *res;
    4068             : 
    4069           0 :         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb, tmp_ctx), LDB_SCOPE_BASE, attrs, NULL);
    4070           0 :         if (ret != LDB_SUCCESS) {
    4071           0 :                 goto failed;
    4072             :         }
    4073             : 
    4074           0 :         if (res->count != 1) {
    4075           0 :                 goto failed;
    4076             :         }
    4077             : 
    4078           0 :         return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
    4079             : 
    4080           0 : failed:
    4081           0 :         DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
    4082           0 :         return NULL;
    4083             : }
    4084             : 
    4085             : /*
    4086             :  * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
    4087             :  * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
    4088             :  */
    4089         734 : const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
    4090             : {
    4091           0 :         char **tokens, *ret;
    4092           0 :         size_t i;
    4093             : 
    4094         734 :         tokens = str_list_make(mem_ctx, cn, " -_");
    4095         734 :         if (tokens == NULL || tokens[0] == NULL) {
    4096           0 :                 return NULL;
    4097             :         }
    4098             : 
    4099             :         /* "tolower()" and "toupper()" should also work properly on 0x00 */
    4100         734 :         tokens[0][0] = tolower(tokens[0][0]);
    4101        2799 :         for (i = 1; tokens[i] != NULL; i++)
    4102        2065 :                 tokens[i][0] = toupper(tokens[i][0]);
    4103             : 
    4104         734 :         ret = talloc_strdup(mem_ctx, tokens[0]);
    4105         734 :         if (ret == NULL) {
    4106           0 :                 talloc_free(tokens);
    4107           0 :                 return NULL;
    4108             :         }
    4109        2799 :         for (i = 1; tokens[i] != NULL; i++) {
    4110        2065 :                 ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
    4111        2065 :                 if (ret == NULL) {
    4112           0 :                         talloc_free(tokens);
    4113           0 :                         return NULL;
    4114             :                 }
    4115             :         }
    4116             : 
    4117         734 :         talloc_free(tokens);
    4118             : 
    4119         734 :         return ret;
    4120             : }
    4121             : 
    4122             : /*
    4123             :  * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
    4124             :  */
    4125     2885364 : int dsdb_functional_level(struct ldb_context *ldb)
    4126             : {
    4127      170435 :         unsigned long long *domainFunctionality =
    4128     2885364 :                 talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), unsigned long long);
    4129     2885364 :         if (!domainFunctionality) {
    4130             :                 /* this is expected during initial provision */
    4131      139420 :                 DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
    4132      139420 :                 return DS_DOMAIN_FUNCTION_2000;
    4133             :         }
    4134     2745944 :         return *domainFunctionality;
    4135             : }
    4136             : 
    4137             : /*
    4138             :  * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
    4139             :  */
    4140        3332 : int dsdb_forest_functional_level(struct ldb_context *ldb)
    4141             : {
    4142          23 :         unsigned long long *forestFunctionality =
    4143        3332 :                 talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), unsigned long long);
    4144        3332 :         if (!forestFunctionality) {
    4145           0 :                 DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
    4146           0 :                 return DS_DOMAIN_FUNCTION_2000;
    4147             :         }
    4148        3332 :         return *forestFunctionality;
    4149             : }
    4150             : 
    4151             : /*
    4152             :  * This detects and returns the DC functional level (DS_DOMAIN_FUNCTION_*)
    4153             :  */
    4154      264778 : int dsdb_dc_functional_level(struct ldb_context *ldb)
    4155             : {
    4156       15100 :         unsigned long long *dcFunctionality =
    4157      264778 :                 talloc_get_type(ldb_get_opaque(ldb, "domainControllerFunctionality"), unsigned long long);
    4158      264778 :         if (!dcFunctionality) {
    4159             :                 /* this is expected during initial provision */
    4160           2 :                 DEBUG(4,(__location__ ": WARNING: domainControllerFunctionality not setup\n"));
    4161           2 :                 return DS_DOMAIN_FUNCTION_2008_R2;
    4162             :         }
    4163      264776 :         return *dcFunctionality;
    4164             : }
    4165             : 
    4166         130 : const char *dsdb_dc_operatingSystemVersion(int dc_functional_level)
    4167             : {
    4168         130 :         const char *operatingSystemVersion = NULL;
    4169             : 
    4170             :         /*
    4171             :          * While we are there also update
    4172             :          * operatingSystem and operatingSystemVersion
    4173             :          * as at least operatingSystemVersion is really
    4174             :          * important for some clients/applications (like exchange).
    4175             :          */
    4176             : 
    4177         130 :         if (dc_functional_level >= DS_DOMAIN_FUNCTION_2016) {
    4178             :                 /* Pretend Windows 2016 */
    4179          24 :                 operatingSystemVersion = "10.0 (14393)";
    4180         104 :         } else if (dc_functional_level >= DS_DOMAIN_FUNCTION_2012_R2) {
    4181             :                 /* Pretend Windows 2012 R2 */
    4182           1 :                 operatingSystemVersion = "6.3 (9600)";
    4183         103 :         } else if (dc_functional_level >= DS_DOMAIN_FUNCTION_2012) {
    4184             :                 /* Pretend Windows 2012 */
    4185           0 :                 operatingSystemVersion = "6.2 (9200)";
    4186             :         } else {
    4187             :                 /* Pretend Windows 2008 R2 */
    4188         103 :                 operatingSystemVersion = "6.1 (7600)";
    4189             :         }
    4190             : 
    4191         130 :         return operatingSystemVersion;
    4192             : }
    4193             : 
    4194          71 : int dsdb_check_and_update_fl(struct ldb_context *ldb_ctx, struct loadparm_context *lp_ctx)
    4195             : {
    4196          71 :         TALLOC_CTX *frame = talloc_stackframe();
    4197           4 :         int ret;
    4198             : 
    4199           4 :         int db_dc_functional_level;
    4200           4 :         int db_domain_functional_level;
    4201           4 :         int db_forest_functional_level;
    4202          71 :         int lp_dc_functional_level = lpcfg_ad_dc_functional_level(lp_ctx);
    4203           4 :         bool am_rodc;
    4204          71 :         struct ldb_message *msg = NULL;
    4205          71 :         struct ldb_dn *dc_ntds_settings_dn = NULL;
    4206          71 :         struct ldb_dn *dc_computer_dn = NULL;
    4207          71 :         const char *operatingSystem = NULL;
    4208          71 :         const char *operatingSystemVersion = NULL;
    4209             : 
    4210          71 :         db_dc_functional_level = dsdb_dc_functional_level(ldb_ctx);
    4211          71 :         db_domain_functional_level = dsdb_functional_level(ldb_ctx);
    4212          71 :         db_forest_functional_level = dsdb_forest_functional_level(ldb_ctx);
    4213             : 
    4214          71 :         if (lp_dc_functional_level < db_domain_functional_level) {
    4215           1 :                 DBG_ERR("Refusing to start as smb.conf 'ad dc functional level' maps to %d, "
    4216             :                         "which is less than the domain functional level of %d\n",
    4217             :                         lp_dc_functional_level, db_domain_functional_level);
    4218           1 :                 TALLOC_FREE(frame);
    4219           1 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
    4220             :         }
    4221             : 
    4222          70 :         if (lp_dc_functional_level < db_forest_functional_level) {
    4223           0 :                 DBG_ERR("Refusing to start as smb.conf 'ad dc functional level' maps to %d, "
    4224             :                         "which is less than the forest functional level of %d\n",
    4225             :                         lp_dc_functional_level, db_forest_functional_level);
    4226           0 :                 TALLOC_FREE(frame);
    4227           0 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
    4228             :         }
    4229             : 
    4230             :         /* Check if we need to update the DB */
    4231          70 :         if (db_dc_functional_level == lp_dc_functional_level) {
    4232             :                 /*
    4233             :                  * Note that this early return means
    4234             :                  * we're not updating operatingSystem and
    4235             :                  * operatingSystemVersion.
    4236             :                  *
    4237             :                  * But at least for now that's
    4238             :                  * exactly what we want.
    4239             :                  */
    4240          67 :                 TALLOC_FREE(frame);
    4241          67 :                 return LDB_SUCCESS;
    4242             :         }
    4243             : 
    4244             :         /* Confirm we are not an RODC before we try a modify */
    4245           3 :         ret = samdb_rodc(ldb_ctx, &am_rodc);
    4246           3 :         if (ret != LDB_SUCCESS) {
    4247           0 :                 DBG_ERR("Failed to determine if this server is an RODC\n");
    4248           0 :                 TALLOC_FREE(frame);
    4249           0 :                 return ret;
    4250             :         }
    4251             : 
    4252           3 :         if (am_rodc) {
    4253           0 :                 DBG_WARNING("Unable to update DC's msDS-Behavior-Version "
    4254             :                             "(from %d to %d) and operatingSystem[Version] "
    4255             :                             "as we are an RODC\n",
    4256             :                             db_dc_functional_level, lp_dc_functional_level);
    4257           0 :                 TALLOC_FREE(frame);
    4258           0 :                 return LDB_SUCCESS;
    4259             :         }
    4260             : 
    4261           3 :         dc_ntds_settings_dn = samdb_ntds_settings_dn(ldb_ctx, frame);
    4262             : 
    4263           3 :         if (dc_ntds_settings_dn == NULL) {
    4264           0 :                 DBG_ERR("Failed to find own NTDS Settings DN\n");
    4265           0 :                 TALLOC_FREE(frame);
    4266           0 :                 return LDB_ERR_NO_SUCH_OBJECT;
    4267             :         }
    4268             : 
    4269             :         /* Now update our msDS-Behavior-Version */
    4270             : 
    4271           3 :         msg = ldb_msg_new(frame);
    4272           3 :         if (msg == NULL) {
    4273           0 :                 DBG_ERR("Failed to allocate message to update msDS-Behavior-Version\n");
    4274           0 :                 TALLOC_FREE(frame);
    4275           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    4276             :         }
    4277             : 
    4278           3 :         msg->dn = dc_ntds_settings_dn;
    4279             : 
    4280           3 :         ret = samdb_msg_add_int(ldb_ctx, frame, msg, "msDS-Behavior-Version", lp_dc_functional_level);
    4281           3 :         if (ret != LDB_SUCCESS) {
    4282           0 :                 DBG_ERR("Failed to set new msDS-Behavior-Version on message\n");
    4283           0 :                 TALLOC_FREE(frame);
    4284           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    4285             :         }
    4286             : 
    4287           3 :         ret = dsdb_replace(ldb_ctx, msg, 0);
    4288           3 :         if (ret != LDB_SUCCESS) {
    4289           0 :                 DBG_ERR("Failed to update DB with new msDS-Behavior-Version on %s: %s\n",
    4290             :                         ldb_dn_get_linearized(dc_ntds_settings_dn),
    4291             :                         ldb_errstring(ldb_ctx));
    4292           0 :                 TALLOC_FREE(frame);
    4293           0 :                 return ret;
    4294             :         }
    4295             : 
    4296             :         /*
    4297             :          * We have to update the opaque because this particular ldb_context
    4298             :          * will not re-read the DB
    4299             :          */
    4300             :         {
    4301           3 :                 unsigned long long *val = talloc(ldb_ctx, unsigned long long);
    4302           3 :                 if (!val) {
    4303           0 :                         TALLOC_FREE(frame);
    4304           0 :                         return LDB_ERR_OPERATIONS_ERROR;
    4305             :                 }
    4306           3 :                 *val = lp_dc_functional_level;
    4307           3 :                 ret = ldb_set_opaque(ldb_ctx,
    4308             :                                      "domainControllerFunctionality", val);
    4309           3 :                 if (ret != LDB_SUCCESS) {
    4310           0 :                         DBG_ERR("Failed to re-set domainControllerFunctionality opaque\n");
    4311           0 :                         TALLOC_FREE(val);
    4312           0 :                         TALLOC_FREE(frame);
    4313           0 :                         return ret;
    4314             :                 }
    4315             :         }
    4316             : 
    4317             :         /*
    4318             :          * While we are there also update
    4319             :          * operatingSystem and operatingSystemVersion
    4320             :          * as at least operatingSystemVersion is really
    4321             :          * important for some clients/applications (like exchange).
    4322             :          */
    4323             : 
    4324           3 :         operatingSystem = talloc_asprintf(frame, "Samba-%s",
    4325             :                                           samba_version_string());
    4326           3 :         if (operatingSystem == NULL) {
    4327           0 :                 TALLOC_FREE(frame);
    4328           0 :                 return ldb_oom(ldb_ctx);
    4329             :         }
    4330             : 
    4331           3 :         operatingSystemVersion = dsdb_dc_operatingSystemVersion(db_dc_functional_level);
    4332             : 
    4333           3 :         ret = samdb_server_reference_dn(ldb_ctx, frame, &dc_computer_dn);
    4334           3 :         if (ret != LDB_SUCCESS) {
    4335           0 :                 DBG_ERR("Failed to get the dc_computer_dn: %s\n",
    4336             :                         ldb_errstring(ldb_ctx));
    4337           0 :                 TALLOC_FREE(frame);
    4338           0 :                 return ret;
    4339             :         }
    4340             : 
    4341           3 :         msg = ldb_msg_new(frame);
    4342           3 :         if (msg == NULL) {
    4343           0 :                 DBG_ERR("Failed to allocate message to update msDS-Behavior-Version\n");
    4344           0 :                 TALLOC_FREE(frame);
    4345           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    4346             :         }
    4347             : 
    4348           3 :         msg->dn = dc_computer_dn;
    4349             : 
    4350           3 :         ret = samdb_msg_add_addval(ldb_ctx, frame, msg,
    4351             :                                    "operatingSystem",
    4352             :                                    operatingSystem);
    4353           3 :         if (ret != LDB_SUCCESS) {
    4354           0 :                 DBG_ERR("Failed to set new operatingSystem on message\n");
    4355           0 :                 TALLOC_FREE(frame);
    4356           0 :                 return ldb_operr(ldb_ctx);
    4357             :         }
    4358             : 
    4359           3 :         ret = samdb_msg_add_addval(ldb_ctx, frame, msg,
    4360             :                                    "operatingSystemVersion",
    4361             :                                    operatingSystemVersion);
    4362           3 :         if (ret != LDB_SUCCESS) {
    4363           0 :                 DBG_ERR("Failed to set new operatingSystemVersion on message\n");
    4364           0 :                 TALLOC_FREE(frame);
    4365           0 :                 return ldb_operr(ldb_ctx);
    4366             :         }
    4367             : 
    4368           3 :         ret = dsdb_replace(ldb_ctx, msg, 0);
    4369           3 :         if (ret != LDB_SUCCESS) {
    4370           0 :                 DBG_ERR("Failed to update DB with new operatingSystem[Version] on %s: %s\n",
    4371             :                         ldb_dn_get_linearized(dc_computer_dn),
    4372             :                         ldb_errstring(ldb_ctx));
    4373           0 :                 TALLOC_FREE(frame);
    4374           0 :                 return ret;
    4375             :         }
    4376             : 
    4377           3 :         TALLOC_FREE(frame);
    4378           2 :         return LDB_SUCCESS;
    4379             : }
    4380             : 
    4381             : 
    4382             : /*
    4383             :   set a GUID in an extended DN structure
    4384             :  */
    4385       24316 : int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
    4386             : {
    4387          41 :         struct ldb_val v;
    4388          41 :         NTSTATUS status;
    4389          41 :         int ret;
    4390             : 
    4391       24316 :         status = GUID_to_ndr_blob(guid, dn, &v);
    4392       24316 :         if (!NT_STATUS_IS_OK(status)) {
    4393           0 :                 return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    4394             :         }
    4395             : 
    4396       24316 :         ret = ldb_dn_set_extended_component(dn, component_name, &v);
    4397       24316 :         data_blob_free(&v);
    4398       24316 :         return ret;
    4399             : }
    4400             : 
    4401             : /*
    4402             :   return a GUID from a extended DN structure
    4403             :  */
    4404    17603043 : NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
    4405             : {
    4406      269084 :         const struct ldb_val *v;
    4407             : 
    4408    17603043 :         v = ldb_dn_get_extended_component(dn, component_name);
    4409    17603043 :         if (v == NULL) {
    4410      207275 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    4411             :         }
    4412             : 
    4413    17395768 :         return GUID_from_ndr_blob(v, guid);
    4414             : }
    4415             : 
    4416             : /*
    4417             :   return a uint64_t from a extended DN structure
    4418             :  */
    4419      128572 : NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
    4420             : {
    4421          24 :         const struct ldb_val *v;
    4422      128572 :         int error = 0;
    4423             : 
    4424      128572 :         v = ldb_dn_get_extended_component(dn, component_name);
    4425      128572 :         if (v == NULL) {
    4426           0 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    4427             :         }
    4428             : 
    4429             :         /* Just check we don't allow the caller to fill our stack */
    4430      128572 :         if (v->length >= 64) {
    4431           0 :                 return NT_STATUS_INVALID_PARAMETER;
    4432      128572 :         } else {
    4433      128572 :                 char s[v->length+1];
    4434      128572 :                 memcpy(s, v->data, v->length);
    4435      128572 :                 s[v->length] = 0;
    4436             : 
    4437      128572 :                 *val = smb_strtoull(s, NULL, 0, &error, SMB_STR_STANDARD);
    4438      128572 :                 if (error != 0) {
    4439           0 :                         return NT_STATUS_INVALID_PARAMETER;
    4440             :                 }
    4441             :         }
    4442      128572 :         return NT_STATUS_OK;
    4443             : }
    4444             : 
    4445             : /*
    4446             :   return a NTTIME from a extended DN structure
    4447             :  */
    4448       48933 : NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
    4449             : {
    4450       48933 :         return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
    4451             : }
    4452             : 
    4453             : /*
    4454             :   return a uint32_t from a extended DN structure
    4455             :  */
    4456     5173805 : NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
    4457             : {
    4458       19558 :         const struct ldb_val *v;
    4459     5173805 :         int error = 0;
    4460             : 
    4461     5173805 :         v = ldb_dn_get_extended_component(dn, component_name);
    4462     5173805 :         if (v == NULL) {
    4463     5030288 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    4464             :         }
    4465             : 
    4466             :         /* Just check we don't allow the caller to fill our stack */
    4467      143517 :         if (v->length >= 32) {
    4468           0 :                 return NT_STATUS_INVALID_PARAMETER;
    4469      143517 :         } else {
    4470      143517 :                 char s[v->length + 1];
    4471      143517 :                 memcpy(s, v->data, v->length);
    4472      143517 :                 s[v->length] = 0;
    4473      143517 :                 *val = smb_strtoul(s, NULL, 0, &error, SMB_STR_STANDARD);
    4474      143517 :                 if (error != 0) {
    4475           0 :                         return NT_STATUS_INVALID_PARAMETER;
    4476             :                 }
    4477             :         }
    4478             : 
    4479      143517 :         return NT_STATUS_OK;
    4480             : }
    4481             : 
    4482             : /*
    4483             :   return a dom_sid from a extended DN structure
    4484             :  */
    4485     3595284 : NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
    4486             : {
    4487      103532 :         const struct ldb_val *sid_blob;
    4488      103532 :         enum ndr_err_code ndr_err;
    4489             : 
    4490     3595284 :         sid_blob = ldb_dn_get_extended_component(dn, component_name);
    4491     3595284 :         if (!sid_blob) {
    4492      621923 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    4493             :         }
    4494             : 
    4495     2973361 :         ndr_err = ndr_pull_struct_blob_all_noalloc(sid_blob, sid,
    4496             :                                                    (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
    4497     2973361 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    4498           0 :                 NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
    4499           0 :                 return status;
    4500             :         }
    4501             : 
    4502     2973361 :         return NT_STATUS_OK;
    4503             : }
    4504             : 
    4505             : 
    4506             : /*
    4507             :   return RMD_FLAGS directly from a ldb_dn
    4508             :   returns 0 if not found
    4509             :  */
    4510      720574 : uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
    4511             : {
    4512      720574 :         uint32_t rmd_flags = 0;
    4513      720574 :         NTSTATUS status = dsdb_get_extended_dn_uint32(dn, &rmd_flags,
    4514             :                                                       "RMD_FLAGS");
    4515      720574 :         if (NT_STATUS_IS_OK(status)) {
    4516       49166 :                 return rmd_flags;
    4517             :         }
    4518      652159 :         return 0;
    4519             : }
    4520             : 
    4521             : /*
    4522             :   return RMD_FLAGS directly from a ldb_val for a DN
    4523             :   returns 0 if RMD_FLAGS is not found
    4524             :  */
    4525    19584097 : uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
    4526             : {
    4527      422854 :         const char *p;
    4528      422854 :         uint32_t flags;
    4529      422854 :         char *end;
    4530    19584097 :         int error = 0;
    4531             : 
    4532    19584097 :         if (val->length < 13) {
    4533           0 :                 return 0;
    4534             :         }
    4535    19584097 :         p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
    4536    19584097 :         if (!p) {
    4537    15351934 :                 return 0;
    4538             :         }
    4539     3818541 :         flags = smb_strtoul(p+11, &end, 10, &error, SMB_STR_STANDARD);
    4540     3818541 :         if (!end || *end != '>' || error != 0) {
    4541             :                 /* it must end in a > */
    4542           0 :                 return 0;
    4543             :         }
    4544     3809309 :         return flags;
    4545             : }
    4546             : 
    4547             : /*
    4548             :   return true if a ldb_val containing a DN in storage form is deleted
    4549             :  */
    4550       57246 : bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
    4551             : {
    4552       57246 :         return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
    4553             : }
    4554             : 
    4555             : /*
    4556             :   return true if a ldb_val containing a DN in storage form is
    4557             :   in the upgraded w2k3 linked attribute format
    4558             :  */
    4559       11986 : bool dsdb_dn_is_upgraded_link_val(const struct ldb_val *val)
    4560             : {
    4561       11986 :         return memmem(val->data, val->length, "<RMD_VERSION=", 13) != NULL;
    4562             : }
    4563             : 
    4564             : /*
    4565             :   return a DN for a wellknown GUID
    4566             :  */
    4567      943562 : int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
    4568             :                       struct ldb_dn *nc_root, const char *wk_guid,
    4569             :                       struct ldb_dn **wkguid_dn)
    4570             : {
    4571      943562 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    4572      943562 :         const char *attrs[] = { NULL };
    4573       77167 :         int ret;
    4574       77167 :         struct ldb_dn *dn;
    4575      943562 :         struct ldb_result *res = NULL;
    4576             : 
    4577      943562 :         if (tmp_ctx == NULL) {
    4578           0 :                 return ldb_oom(samdb);
    4579             :         }
    4580             : 
    4581             :         /* construct the magic WKGUID DN */
    4582      943562 :         dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
    4583             :                             wk_guid, ldb_dn_get_linearized(nc_root));
    4584      943562 :         if (!wkguid_dn) {
    4585           0 :                 talloc_free(tmp_ctx);
    4586           0 :                 return ldb_operr(samdb);
    4587             :         }
    4588             : 
    4589      943562 :         ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
    4590             :                              DSDB_SEARCH_SHOW_DELETED |
    4591             :                              DSDB_SEARCH_SHOW_RECYCLED);
    4592      943562 :         if (ret != LDB_SUCCESS) {
    4593      553144 :                 talloc_free(tmp_ctx);
    4594      553144 :                 return ret;
    4595             :         }
    4596             :         /* fix clang warning */
    4597      390418 :         if (res == NULL){
    4598           0 :                 talloc_free(tmp_ctx);
    4599           0 :                 return LDB_ERR_OTHER;
    4600             :         }
    4601             : 
    4602      390418 :         (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
    4603      390418 :         talloc_free(tmp_ctx);
    4604      390418 :         return LDB_SUCCESS;
    4605             : }
    4606             : 
    4607             : 
    4608        2355 : static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
    4609             : {
    4610        2355 :         return ldb_dn_compare(*dn1, *dn2);
    4611             : }
    4612             : 
    4613             : /*
    4614             :   find a NC root given a DN within the NC by reading the rootDSE namingContexts
    4615             :  */
    4616         985 : static int dsdb_find_nc_root_string_based(struct ldb_context *samdb,
    4617             :                                           TALLOC_CTX *mem_ctx,
    4618             :                                           struct ldb_dn *dn,
    4619             :                                           struct ldb_dn **nc_root)
    4620             : {
    4621         985 :         const char *root_attrs[] = { "namingContexts", NULL };
    4622          44 :         TALLOC_CTX *tmp_ctx;
    4623          44 :         int ret;
    4624          44 :         struct ldb_message_element *el;
    4625          44 :         struct ldb_result *root_res;
    4626          44 :         unsigned int i;
    4627          44 :         struct ldb_dn **nc_dns;
    4628             : 
    4629         985 :         tmp_ctx = talloc_new(samdb);
    4630         985 :         if (tmp_ctx == NULL) {
    4631           0 :                 return ldb_oom(samdb);
    4632             :         }
    4633             : 
    4634         985 :         ret = ldb_search(samdb, tmp_ctx, &root_res,
    4635             :                          ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
    4636         985 :         if (ret != LDB_SUCCESS || root_res->count == 0) {
    4637           0 :                 DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
    4638           0 :                 talloc_free(tmp_ctx);
    4639           0 :                 return ret;
    4640             :         }
    4641             : 
    4642         985 :         el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
    4643         985 :         if ((el == NULL) || (el->num_values < 3)) {
    4644          44 :                 struct ldb_message *tmp_msg;
    4645             : 
    4646         874 :                 DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list.\n"));
    4647             : 
    4648             :                 /* This generates a temporary list of NCs in order to let the
    4649             :                  * provisioning work. */
    4650         874 :                 tmp_msg = ldb_msg_new(tmp_ctx);
    4651         874 :                 if (tmp_msg == NULL) {
    4652           0 :                         talloc_free(tmp_ctx);
    4653           0 :                         return ldb_oom(samdb);
    4654             :                 }
    4655         874 :                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
    4656             :                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb)));
    4657         874 :                 if (ret != LDB_SUCCESS) {
    4658           0 :                         talloc_free(tmp_ctx);
    4659           0 :                         return ret;
    4660             :                 }
    4661         874 :                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
    4662             :                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb)));
    4663         874 :                 if (ret != LDB_SUCCESS) {
    4664           0 :                         talloc_free(tmp_ctx);
    4665           0 :                         return ret;
    4666             :                 }
    4667         874 :                 ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
    4668             :                                                ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb)));
    4669         874 :                 if (ret != LDB_SUCCESS) {
    4670           0 :                         talloc_free(tmp_ctx);
    4671           0 :                         return ret;
    4672             :                 }
    4673         874 :                 el = &tmp_msg->elements[0];
    4674             :         }
    4675             : 
    4676         985 :        nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
    4677         985 :        if (!nc_dns) {
    4678           0 :                talloc_free(tmp_ctx);
    4679           0 :                return ldb_oom(samdb);
    4680             :        }
    4681             : 
    4682        4114 :        for (i=0; i<el->num_values; i++) {
    4683        3129 :                nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
    4684        3129 :                if (nc_dns[i] == NULL) {
    4685           0 :                        talloc_free(tmp_ctx);
    4686           0 :                        return ldb_operr(samdb);
    4687             :                }
    4688             :        }
    4689             : 
    4690         985 :        TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
    4691             : 
    4692        3099 :        for (i=0; i<el->num_values; i++) {
    4693        3087 :                if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
    4694         973 :                        (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
    4695         973 :                        talloc_free(tmp_ctx);
    4696         973 :                        return LDB_SUCCESS;
    4697             :                }
    4698             :        }
    4699             : 
    4700          12 :        talloc_free(tmp_ctx);
    4701          12 :        return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT, __func__);
    4702             : }
    4703             : 
    4704             : struct dsdb_get_partition_and_dn {
    4705             :         TALLOC_CTX *mem_ctx;
    4706             :         unsigned int count;
    4707             :         struct ldb_dn *dn;
    4708             :         struct ldb_dn *partition_dn;
    4709             :         bool want_partition_dn;
    4710             : };
    4711             : 
    4712     9960731 : static int dsdb_get_partition_and_dn(struct ldb_request *req,
    4713             :                                      struct ldb_reply *ares)
    4714             : {
    4715      775092 :         int ret;
    4716     9960731 :         struct dsdb_get_partition_and_dn *context = req->context;
    4717     9960731 :         struct ldb_control *partition_ctrl = NULL;
    4718     9960731 :         struct dsdb_control_current_partition *partition = NULL;
    4719             : 
    4720     9960731 :         if (!ares) {
    4721           0 :                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    4722             :         }
    4723     9960731 :         if (ares->error != LDB_SUCCESS
    4724     2153513 :             && ares->error != LDB_ERR_NO_SUCH_OBJECT) {
    4725           1 :                 return ldb_request_done(req, ares->error);
    4726             :         }
    4727             : 
    4728     9960730 :         switch (ares->type) {
    4729     4165794 :         case LDB_REPLY_ENTRY:
    4730     4165794 :                 if (context->count != 0) {
    4731           0 :                         return ldb_request_done(req,
    4732             :                                                 LDB_ERR_CONSTRAINT_VIOLATION);
    4733             :                 }
    4734     4165794 :                 context->count++;
    4735             : 
    4736     4165794 :                 context->dn = talloc_steal(context->mem_ctx,
    4737             :                                            ares->message->dn);
    4738     4165794 :                 break;
    4739             : 
    4740           0 :         case LDB_REPLY_REFERRAL:
    4741           0 :                 talloc_free(ares);
    4742           0 :                 return ldb_request_done(req, LDB_SUCCESS);
    4743             : 
    4744     5794936 :         case LDB_REPLY_DONE:
    4745      512907 :                 partition_ctrl
    4746     5794936 :                         = ldb_reply_get_control(ares,
    4747             :                                                 DSDB_CONTROL_CURRENT_PARTITION_OID);
    4748     5794936 :                 if (!context->want_partition_dn ||
    4749             :                         partition_ctrl == NULL) {
    4750       16726 :                         ret = ares->error;
    4751       16726 :                         talloc_free(ares);
    4752             : 
    4753       16726 :                         return ldb_request_done(req, ret);
    4754             :                 }
    4755             : 
    4756      512863 :                 partition
    4757     5778210 :                         = talloc_get_type_abort(partition_ctrl->data,
    4758             :                                                 struct dsdb_control_current_partition);
    4759      512863 :                 context->partition_dn
    4760     5778210 :                         = ldb_dn_copy(context->mem_ctx, partition->dn);
    4761     5778210 :                 if (context->partition_dn == NULL) {
    4762           0 :                         return ldb_request_done(req,
    4763             :                                                 LDB_ERR_OPERATIONS_ERROR);
    4764             :                 }
    4765             : 
    4766     5778210 :                 ret = ares->error;
    4767     5778210 :                 talloc_free(ares);
    4768             : 
    4769     5778210 :                 return ldb_request_done(req, ret);
    4770             :         }
    4771             : 
    4772     4165794 :         talloc_free(ares);
    4773     4165794 :         return LDB_SUCCESS;
    4774             : }
    4775             : 
    4776             : /*
    4777             :   find a NC root given a DN within the NC
    4778             :  */
    4779     5794937 : int dsdb_normalise_dn_and_find_nc_root(struct ldb_context *samdb,
    4780             :                                        TALLOC_CTX *mem_ctx,
    4781             :                                        struct ldb_dn *dn,
    4782             :                                        struct ldb_dn **normalised_dn,
    4783             :                                        struct ldb_dn **nc_root)
    4784             : {
    4785      512907 :         TALLOC_CTX *tmp_ctx;
    4786      512907 :         int ret;
    4787      512907 :         struct ldb_request *req;
    4788      512907 :         struct ldb_result *res;
    4789     5794937 :         struct ldb_dn *search_dn = dn;
    4790      512907 :         static const char * attrs[] = { NULL };
    4791     5794937 :         bool has_extended = ldb_dn_has_extended(dn);
    4792     5794937 :         bool has_normal_components = ldb_dn_get_comp_num(dn) >= 1;
    4793     5794937 :         struct dsdb_get_partition_and_dn context = {
    4794             :                 .mem_ctx = mem_ctx,
    4795     5794937 :                 .want_partition_dn = nc_root != NULL
    4796             :         };
    4797             : 
    4798     5794937 :         if (!has_extended && !has_normal_components) {
    4799           0 :                 return ldb_error(samdb, LDB_ERR_NO_SUCH_OBJECT,
    4800             :                                  "Request for NC root for rootDSE (\"\") denied.");
    4801             :         }
    4802             : 
    4803     5794937 :         tmp_ctx = talloc_new(samdb);
    4804     5794937 :         if (tmp_ctx == NULL) {
    4805           0 :                 return ldb_oom(samdb);
    4806             :         }
    4807             : 
    4808     5794937 :         res = talloc_zero(tmp_ctx, struct ldb_result);
    4809     5794937 :         if (res == NULL) {
    4810           0 :                 talloc_free(tmp_ctx);
    4811           0 :                 return ldb_oom(samdb);
    4812             :         }
    4813             : 
    4814     5794937 :         if (has_extended && has_normal_components) {
    4815      176773 :                 bool minimise_ok;
    4816     2863405 :                 search_dn = ldb_dn_copy(tmp_ctx, dn);
    4817     2863405 :                 if (search_dn == NULL) {
    4818           0 :                         talloc_free(tmp_ctx);
    4819           0 :                         return ldb_oom(samdb);
    4820             :                 }
    4821     2863405 :                 minimise_ok = ldb_dn_minimise(search_dn);
    4822     2863405 :                 if (!minimise_ok) {
    4823           0 :                         talloc_free(tmp_ctx);
    4824           0 :                         return ldb_operr(samdb);
    4825             :                 }
    4826             :         }
    4827             : 
    4828     5794937 :         ret = ldb_build_search_req(&req, samdb, tmp_ctx,
    4829             :                                    search_dn,
    4830             :                                    LDB_SCOPE_BASE,
    4831             :                                    NULL,
    4832             :                                    attrs,
    4833             :                                    NULL,
    4834             :                                    &context,
    4835             :                                    dsdb_get_partition_and_dn,
    4836             :                                    NULL);
    4837     5794937 :         if (ret != LDB_SUCCESS) {
    4838           0 :                 talloc_free(tmp_ctx);
    4839           0 :                 return ret;
    4840             :         }
    4841             : 
    4842     5794937 :         ret = ldb_request_add_control(req,
    4843             :                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
    4844             :                                       false, NULL);
    4845     5794937 :         if (ret != LDB_SUCCESS) {
    4846           0 :                 talloc_free(tmp_ctx);
    4847           0 :                 return ret;
    4848             :         }
    4849             : 
    4850     5794937 :         ret = dsdb_request_add_controls(req,
    4851             :                                         DSDB_SEARCH_SHOW_RECYCLED|
    4852             :                                         DSDB_SEARCH_SHOW_DELETED|
    4853             :                                         DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT);
    4854     5794937 :         if (ret != LDB_SUCCESS) {
    4855           0 :                 talloc_free(tmp_ctx);
    4856           0 :                 return ret;
    4857             :         }
    4858             : 
    4859     5794937 :         ret = ldb_request(samdb, req);
    4860     5794937 :         if (ret == LDB_SUCCESS) {
    4861     5794936 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    4862             :         }
    4863             : 
    4864             :         /*
    4865             :          * This could be a new DN, not in the DB, which is OK.  If we
    4866             :          * don't need the normalised DN, we can continue.
    4867             :          *
    4868             :          * We may be told the partition it would be in in the search
    4869             :          * reply control, or if not we can do a string-based match.
    4870             :          */
    4871             : 
    4872     5794937 :         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    4873     1629142 :                 if (normalised_dn != NULL) {
    4874           8 :                         talloc_free(tmp_ctx);
    4875           8 :                         return ret;
    4876             :                 }
    4877     1629134 :                 ret = LDB_SUCCESS;
    4878     1629134 :                 ldb_reset_err_string(samdb);
    4879     4165795 :         } else if (ret != LDB_SUCCESS) {
    4880           1 :                 talloc_free(tmp_ctx);
    4881           1 :                 return ret;
    4882             :         }
    4883             : 
    4884     5794928 :         if (normalised_dn != NULL) {
    4885       18694 :                 if (context.count != 1) {
    4886             :                         /* No results */
    4887           0 :                         ldb_asprintf_errstring(samdb,
    4888             :                                                "Request for NC root for %s failed to return any results.",
    4889             :                                                ldb_dn_get_linearized(dn));
    4890           0 :                         talloc_free(tmp_ctx);
    4891           0 :                         return LDB_ERR_NO_SUCH_OBJECT;
    4892             :                 }
    4893       18694 :                 *normalised_dn = context.dn;
    4894             :         }
    4895             : 
    4896             :         /*
    4897             :          * If the user did not need to find the nc_root,
    4898             :          * we are done
    4899             :          */
    4900     5794928 :         if (nc_root == NULL) {
    4901       15725 :                 talloc_free(tmp_ctx);
    4902       15725 :                 return ret;
    4903             :         }
    4904             : 
    4905             :         /*
    4906             :          * When we are working locally, both for the case were
    4907             :          * we find the DN, and the case where we fail, we get
    4908             :          * back via controls the partition it was in or should
    4909             :          * have been in, to return to the client
    4910             :          */
    4911     5779203 :         if (context.partition_dn != NULL) {
    4912     5778210 :                 (*nc_root) = context.partition_dn;
    4913             : 
    4914     5778210 :                 talloc_free(tmp_ctx);
    4915     5778210 :                 return ret;
    4916             :         }
    4917             : 
    4918             :         /*
    4919             :          * This is a remote operation, which is a little harder as we
    4920             :          * have a work out the nc_root from the list of NCs. If we did
    4921             :          * at least resolve the DN to a string, get that now, it makes
    4922             :          * the string-based match below possible for a GUID-based
    4923             :          * input over remote LDAP.
    4924             :          */
    4925         993 :         if (context.dn) {
    4926           6 :                 dn = context.dn;
    4927         987 :         } else if (has_extended && !has_normal_components) {
    4928           8 :                 ldb_asprintf_errstring(samdb,
    4929             :                                        "Cannot determine NC root "
    4930             :                                        "for a not-found bare extended DN %s.",
    4931             :                                        ldb_dn_get_extended_linearized(tmp_ctx, dn, 1));
    4932           8 :                 talloc_free(tmp_ctx);
    4933           8 :                 return LDB_ERR_NO_SUCH_OBJECT;
    4934             :         }
    4935             : 
    4936             :         /*
    4937             :          * Either we are working against a remote LDAP
    4938             :          * server or the object doesn't exist locally.
    4939             :          *
    4940             :          * This means any GUID that was present in the DN
    4941             :          * therefore could not be evaluated, so do a
    4942             :          * string-based match instead.
    4943             :          */
    4944         985 :         talloc_free(tmp_ctx);
    4945         985 :         return dsdb_find_nc_root_string_based(samdb,
    4946             :                                               mem_ctx,
    4947             :                                               dn,
    4948             :                                               nc_root);
    4949             : }
    4950             : 
    4951             : /*
    4952             :   find a NC root given a DN within the NC
    4953             :  */
    4954     5757953 : int dsdb_find_nc_root(struct ldb_context *samdb,
    4955             :                       TALLOC_CTX *mem_ctx,
    4956             :                       struct ldb_dn *dn,
    4957             :                       struct ldb_dn **nc_root)
    4958             : {
    4959     5757953 :         return dsdb_normalise_dn_and_find_nc_root(samdb,
    4960             :                                                   mem_ctx,
    4961             :                                                   dn,
    4962             :                                                   NULL,
    4963             :                                                   nc_root);
    4964             : }
    4965             : 
    4966             : /*
    4967             :   find the deleted objects DN for any object, by looking for the NC
    4968             :   root, then looking up the wellknown GUID
    4969             :  */
    4970      373153 : int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
    4971             :                                 TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
    4972             :                                 struct ldb_dn **do_dn)
    4973             : {
    4974         112 :         struct ldb_dn *nc_root;
    4975         112 :         int ret;
    4976             : 
    4977      373153 :         ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
    4978      373153 :         if (ret != LDB_SUCCESS) {
    4979           0 :                 return ret;
    4980             :         }
    4981             : 
    4982      373153 :         ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
    4983      373153 :         talloc_free(nc_root);
    4984      373153 :         return ret;
    4985             : }
    4986             : 
    4987             : /*
    4988             :   return the tombstoneLifetime, in days
    4989             :  */
    4990          59 : int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
    4991             : {
    4992           2 :         struct ldb_dn *dn;
    4993          59 :         dn = ldb_get_config_basedn(ldb);
    4994          59 :         if (!dn) {
    4995           0 :                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
    4996             :         }
    4997          59 :         dn = ldb_dn_copy(ldb, dn);
    4998          59 :         if (!dn) {
    4999           0 :                 return ldb_operr(ldb);
    5000             :         }
    5001             :         /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
    5002             :          be a wellknown GUID for this */
    5003          59 :         if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
    5004           0 :                 talloc_free(dn);
    5005           0 :                 return ldb_operr(ldb);
    5006             :         }
    5007             : 
    5008          59 :         *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
    5009          59 :         talloc_free(dn);
    5010          59 :         return LDB_SUCCESS;
    5011             : }
    5012             : 
    5013             : /*
    5014             :   compare a ldb_val to a string case insensitively
    5015             :  */
    5016           0 : int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
    5017             : {
    5018           0 :         size_t len = strlen(s);
    5019           0 :         int ret;
    5020           0 :         if (len > v->length) return 1;
    5021           0 :         ret = strncasecmp(s, (const char *)v->data, v->length);
    5022           0 :         if (ret != 0) return ret;
    5023           0 :         if (v->length > len && v->data[len] != 0) {
    5024           0 :                 return -1;
    5025             :         }
    5026           0 :         return 0;
    5027             : }
    5028             : 
    5029             : 
    5030             : /*
    5031             :   load the UDV for a partition in v2 format
    5032             :   The list is returned sorted, and with our local cursor added
    5033             :  */
    5034       18345 : int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
    5035             :                      struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
    5036             : {
    5037          20 :         static const char *attrs[] = { "replUpToDateVector", NULL };
    5038       18345 :         struct ldb_result *r = NULL;
    5039          20 :         const struct ldb_val *ouv_value;
    5040          20 :         unsigned int i;
    5041          20 :         int ret;
    5042       18345 :         uint64_t highest_usn = 0;
    5043          20 :         const struct GUID *our_invocation_id;
    5044          20 :         static const struct timeval tv1970;
    5045       18345 :         NTTIME nt1970 = timeval_to_nttime(&tv1970);
    5046             : 
    5047       18345 :         ret = dsdb_search_dn(samdb, mem_ctx, &r, dn, attrs, DSDB_SEARCH_SHOW_RECYCLED|DSDB_SEARCH_SHOW_DELETED);
    5048       18345 :         if (ret != LDB_SUCCESS) {
    5049           0 :                 return ret;
    5050             :         }
    5051             :         /* fix clang warning */
    5052       18345 :         if (r == NULL) {
    5053           0 :                 return LDB_ERR_OTHER;
    5054             :         }
    5055       18345 :         ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
    5056       18345 :         if (ouv_value) {
    5057           0 :                 enum ndr_err_code ndr_err;
    5058           0 :                 struct replUpToDateVectorBlob ouv;
    5059             : 
    5060       11445 :                 ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
    5061             :                                                (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
    5062       11445 :                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    5063           0 :                         talloc_free(r);
    5064           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    5065             :                 }
    5066       11445 :                 if (ouv.version != 2) {
    5067             :                         /* we always store as version 2, and
    5068             :                          * replUpToDateVector is not replicated
    5069             :                          */
    5070           0 :                         talloc_free(r);
    5071           0 :                         return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
    5072             :                 }
    5073             : 
    5074       11445 :                 *count = ouv.ctr.ctr2.count;
    5075       11445 :                 *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
    5076             :         } else {
    5077        6900 :                 *count = 0;
    5078        6900 :                 *cursors = NULL;
    5079             :         }
    5080             : 
    5081       18345 :         talloc_free(r);
    5082             : 
    5083       18345 :         our_invocation_id = samdb_ntds_invocation_id(samdb);
    5084       18345 :         if (!our_invocation_id) {
    5085           0 :                 DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
    5086           0 :                 talloc_free(*cursors);
    5087           0 :                 return ldb_operr(samdb);
    5088             :         }
    5089             : 
    5090       18345 :         ret = ldb_sequence_number(samdb, LDB_SEQ_HIGHEST_SEQ, &highest_usn);
    5091       18345 :         if (ret != LDB_SUCCESS) {
    5092             :                 /* nothing to add - this can happen after a vampire */
    5093         315 :                 TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
    5094         315 :                 return LDB_SUCCESS;
    5095             :         }
    5096             : 
    5097       30857 :         for (i=0; i<*count; i++) {
    5098       12827 :                 if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
    5099           0 :                         (*cursors)[i].highest_usn = highest_usn;
    5100           0 :                         (*cursors)[i].last_sync_success = nt1970;
    5101           0 :                         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
    5102           0 :                         return LDB_SUCCESS;
    5103             :                 }
    5104             :         }
    5105             : 
    5106       18030 :         (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
    5107       18030 :         if (! *cursors) {
    5108           0 :                 return ldb_oom(samdb);
    5109             :         }
    5110             : 
    5111       18030 :         (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
    5112       18030 :         (*cursors)[*count].highest_usn = highest_usn;
    5113       18030 :         (*cursors)[*count].last_sync_success = nt1970;
    5114       18030 :         (*count)++;
    5115             : 
    5116       18030 :         TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
    5117             : 
    5118       18010 :         return LDB_SUCCESS;
    5119             : }
    5120             : 
    5121             : /*
    5122             :   load the UDV for a partition in version 1 format
    5123             :   The list is returned sorted, and with our local cursor added
    5124             :  */
    5125           0 : int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
    5126             :                      struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
    5127             : {
    5128           0 :         struct drsuapi_DsReplicaCursor2 *v2 = NULL;
    5129           0 :         uint32_t i;
    5130           0 :         int ret;
    5131             : 
    5132           0 :         ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
    5133           0 :         if (ret != LDB_SUCCESS) {
    5134           0 :                 return ret;
    5135             :         }
    5136             : 
    5137           0 :         if (*count == 0) {
    5138           0 :                 talloc_free(v2);
    5139           0 :                 *cursors = NULL;
    5140           0 :                 return LDB_SUCCESS;
    5141             :         }
    5142             : 
    5143           0 :         *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
    5144           0 :         if (*cursors == NULL) {
    5145           0 :                 talloc_free(v2);
    5146           0 :                 return ldb_oom(samdb);
    5147             :         }
    5148             : 
    5149           0 :         for (i=0; i<*count; i++) {
    5150           0 :                 (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
    5151           0 :                 (*cursors)[i].highest_usn = v2[i].highest_usn;
    5152             :         }
    5153           0 :         talloc_free(v2);
    5154           0 :         return LDB_SUCCESS;
    5155             : }
    5156             : 
    5157             : /*
    5158             :   add a set of controls to a ldb_request structure based on a set of
    5159             :   flags. See util.h for a list of available flags
    5160             :  */
    5161    71551183 : int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
    5162             : {
    5163     3255977 :         int ret;
    5164    71551183 :         if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
    5165      469496 :                 struct ldb_search_options_control *options;
    5166             :                 /* Using the phantom root control allows us to search all partitions */
    5167    19813605 :                 options = talloc(req, struct ldb_search_options_control);
    5168    19813605 :                 if (options == NULL) {
    5169           0 :                         return LDB_ERR_OPERATIONS_ERROR;
    5170             :                 }
    5171    19813605 :                 options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
    5172             : 
    5173    19813605 :                 ret = ldb_request_add_control(req,
    5174             :                                               LDB_CONTROL_SEARCH_OPTIONS_OID,
    5175             :                                               true, options);
    5176    19813605 :                 if (ret != LDB_SUCCESS) {
    5177           0 :                         return ret;
    5178             :                 }
    5179             :         }
    5180             : 
    5181    71551183 :         if (dsdb_flags & DSDB_SEARCH_NO_GLOBAL_CATALOG) {
    5182      333716 :                 ret = ldb_request_add_control(req,
    5183             :                                               DSDB_CONTROL_NO_GLOBAL_CATALOG,
    5184             :                                               false, NULL);
    5185      333716 :                 if (ret != LDB_SUCCESS) {
    5186           0 :                         return ret;
    5187             :                 }
    5188             :         }
    5189             : 
    5190    71551183 :         if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
    5191    22001930 :                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
    5192    22001930 :                 if (ret != LDB_SUCCESS) {
    5193           0 :                         return ret;
    5194             :                 }
    5195             :         }
    5196             : 
    5197    71551183 :         if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
    5198    34021687 :                 ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
    5199    34021687 :                 if (ret != LDB_SUCCESS) {
    5200           0 :                         return ret;
    5201             :                 }
    5202             :         }
    5203             : 
    5204    71551183 :         if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
    5205     7541856 :                 ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, false, NULL);
    5206     7541856 :                 if (ret != LDB_SUCCESS) {
    5207           0 :                         return ret;
    5208             :                 }
    5209             :         }
    5210             : 
    5211    71551183 :         if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
    5212    18086365 :                 struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
    5213    18086365 :                 if (!extended_ctrl) {
    5214           0 :                         return LDB_ERR_OPERATIONS_ERROR;
    5215             :                 }
    5216    18086365 :                 extended_ctrl->type = 1;
    5217             : 
    5218    18086365 :                 ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
    5219    18086365 :                 if (ret != LDB_SUCCESS) {
    5220           0 :                         return ret;
    5221             :                 }
    5222             :         }
    5223             : 
    5224    71551183 :         if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
    5225     1422223 :                 ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
    5226     1422223 :                 if (ret != LDB_SUCCESS) {
    5227           0 :                         return ret;
    5228             :                 }
    5229             :         }
    5230             : 
    5231    71551183 :         if (dsdb_flags & DSDB_MODIFY_RELAX) {
    5232          89 :                 ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
    5233          89 :                 if (ret != LDB_SUCCESS) {
    5234           0 :                         return ret;
    5235             :                 }
    5236             :         }
    5237             : 
    5238    71551183 :         if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
    5239          10 :                 ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
    5240          10 :                 if (ret != LDB_SUCCESS) {
    5241           0 :                         return ret;
    5242             :                 }
    5243             :         }
    5244             : 
    5245    71551183 :         if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
    5246    19408718 :                 ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
    5247    19408718 :                 if (ret != LDB_SUCCESS) {
    5248           0 :                         return ret;
    5249             :                 }
    5250             :         }
    5251             : 
    5252    71551183 :         if (dsdb_flags & DSDB_TREE_DELETE) {
    5253       29735 :                 ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
    5254       29735 :                 if (ret != LDB_SUCCESS) {
    5255           0 :                         return ret;
    5256             :                 }
    5257             :         }
    5258             : 
    5259    71551183 :         if (dsdb_flags & DSDB_PROVISION) {
    5260           0 :                 ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
    5261           0 :                 if (ret != LDB_SUCCESS) {
    5262           0 :                         return ret;
    5263             :                 }
    5264             :         }
    5265             : 
    5266             :         /* This is a special control to bypass the password_hash module for use in pdb_samba4 for Samba3 upgrades */
    5267    71551183 :         if (dsdb_flags & DSDB_BYPASS_PASSWORD_HASH) {
    5268          11 :                 ret = ldb_request_add_control(req, DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID, true, NULL);
    5269          11 :                 if (ret != LDB_SUCCESS) {
    5270           0 :                         return ret;
    5271             :                 }
    5272             :         }
    5273             : 
    5274    71551183 :         if (dsdb_flags & DSDB_PASSWORD_BYPASS_LAST_SET) {
    5275             :                 /*
    5276             :                  * This must not be critical, as it will only be
    5277             :                  * handled (and need to be handled) if the other
    5278             :                  * attributes in the request bring password_hash into
    5279             :                  * action
    5280             :                  */
    5281          16 :                 ret = ldb_request_add_control(req, DSDB_CONTROL_PASSWORD_BYPASS_LAST_SET_OID, false, NULL);
    5282          16 :                 if (ret != LDB_SUCCESS) {
    5283           0 :                         return ret;
    5284             :                 }
    5285             :         }
    5286             : 
    5287    71551183 :         if (dsdb_flags & DSDB_REPLMD_VANISH_LINKS) {
    5288       29429 :                 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLMD_VANISH_LINKS, true, NULL);
    5289       29429 :                 if (ret != LDB_SUCCESS) {
    5290           0 :                         return ret;
    5291             :                 }
    5292             :         }
    5293             : 
    5294    71551183 :         if (dsdb_flags & DSDB_MODIFY_PARTIAL_REPLICA) {
    5295           0 :                 ret = ldb_request_add_control(req, DSDB_CONTROL_PARTIAL_REPLICA, false, NULL);
    5296           0 :                 if (ret != LDB_SUCCESS) {
    5297           0 :                         return ret;
    5298             :                 }
    5299             :         }
    5300             : 
    5301    71551183 :         if (dsdb_flags & DSDB_FLAG_REPLICATED_UPDATE) {
    5302          50 :                 ret = ldb_request_add_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID, false, NULL);
    5303          50 :                 if (ret != LDB_SUCCESS) {
    5304           0 :                         return ret;
    5305             :                 }
    5306             :         }
    5307             : 
    5308    71551183 :         if (dsdb_flags & DSDB_FLAG_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE) {
    5309         147 :                 ret = ldb_request_add_control(req, DSDB_CONTROL_FORCE_ALLOW_VALIDATED_DNS_HOSTNAME_SPN_WRITE_OID, true, NULL);
    5310         147 :                 if (ret != LDB_SUCCESS) {
    5311           0 :                         return ret;
    5312             :                 }
    5313             :         }
    5314             : 
    5315    71551183 :         if (dsdb_flags & DSDB_MARK_REQ_UNTRUSTED) {
    5316        5645 :                 ldb_req_mark_untrusted(req);
    5317             :         }
    5318             : 
    5319    68295206 :         return LDB_SUCCESS;
    5320             : }
    5321             : 
    5322             : /*
    5323             :    returns true if a control with the specified "oid" exists
    5324             : */
    5325    89295531 : bool dsdb_request_has_control(struct ldb_request *req, const char *oid)
    5326             : {
    5327    89295531 :         return (ldb_request_get_control(req, oid) != NULL);
    5328             : }
    5329             : 
    5330             : /*
    5331             :   an add with a set of controls
    5332             : */
    5333         101 : int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
    5334             :              uint32_t dsdb_flags)
    5335             : {
    5336          22 :         struct ldb_request *req;
    5337          22 :         int ret;
    5338             : 
    5339         101 :         ret = ldb_build_add_req(&req, ldb, ldb,
    5340             :                                 message,
    5341             :                                 NULL,
    5342             :                                 NULL,
    5343             :                                 ldb_op_default_callback,
    5344             :                                 NULL);
    5345             : 
    5346         101 :         if (ret != LDB_SUCCESS) return ret;
    5347             : 
    5348         101 :         ret = dsdb_request_add_controls(req, dsdb_flags);
    5349         101 :         if (ret != LDB_SUCCESS) {
    5350           0 :                 talloc_free(req);
    5351           0 :                 return ret;
    5352             :         }
    5353             : 
    5354         101 :         ret = dsdb_autotransaction_request(ldb, req);
    5355             : 
    5356         101 :         talloc_free(req);
    5357         101 :         return ret;
    5358             : }
    5359             : 
    5360             : /*
    5361             :   a modify with a set of controls
    5362             : */
    5363       15427 : int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
    5364             :                 uint32_t dsdb_flags)
    5365             : {
    5366         229 :         struct ldb_request *req;
    5367         229 :         int ret;
    5368             : 
    5369       15427 :         ret = ldb_build_mod_req(&req, ldb, ldb,
    5370             :                                 message,
    5371             :                                 NULL,
    5372             :                                 NULL,
    5373             :                                 ldb_op_default_callback,
    5374             :                                 NULL);
    5375             : 
    5376       15427 :         if (ret != LDB_SUCCESS) return ret;
    5377             : 
    5378       15427 :         ret = dsdb_request_add_controls(req, dsdb_flags);
    5379       15427 :         if (ret != LDB_SUCCESS) {
    5380           0 :                 talloc_free(req);
    5381           0 :                 return ret;
    5382             :         }
    5383             : 
    5384       15427 :         ret = dsdb_autotransaction_request(ldb, req);
    5385             : 
    5386       15427 :         talloc_free(req);
    5387       15427 :         return ret;
    5388             : }
    5389             : 
    5390             : /*
    5391             :   a delete with a set of flags
    5392             : */
    5393         437 : int dsdb_delete(struct ldb_context *ldb, struct ldb_dn *dn,
    5394             :                 uint32_t dsdb_flags)
    5395             : {
    5396           7 :         struct ldb_request *req;
    5397           7 :         int ret;
    5398             : 
    5399         437 :         ret = ldb_build_del_req(&req, ldb, ldb,
    5400             :                                 dn,
    5401             :                                 NULL,
    5402             :                                 NULL,
    5403             :                                 ldb_op_default_callback,
    5404             :                                 NULL);
    5405             : 
    5406         437 :         if (ret != LDB_SUCCESS) return ret;
    5407             : 
    5408         437 :         ret = dsdb_request_add_controls(req, dsdb_flags);
    5409         437 :         if (ret != LDB_SUCCESS) {
    5410           0 :                 talloc_free(req);
    5411           0 :                 return ret;
    5412             :         }
    5413             : 
    5414         437 :         ret = dsdb_autotransaction_request(ldb, req);
    5415             : 
    5416         437 :         talloc_free(req);
    5417         437 :         return ret;
    5418             : }
    5419             : 
    5420             : /*
    5421             :   like dsdb_modify() but set all the element flags to
    5422             :   LDB_FLAG_MOD_REPLACE
    5423             :  */
    5424        3096 : int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
    5425             : {
    5426         205 :         unsigned int i;
    5427             : 
    5428             :         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
    5429       10218 :         for (i=0;i<msg->num_elements;i++) {
    5430        7122 :                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
    5431             :         }
    5432             : 
    5433        3096 :         return dsdb_modify(ldb, msg, dsdb_flags);
    5434             : }
    5435             : 
    5436      341231 : const char *dsdb_search_scope_as_string(enum ldb_scope scope)
    5437             : {
    5438         249 :         const char *scope_str;
    5439             : 
    5440      341231 :         switch (scope) {
    5441      173098 :         case LDB_SCOPE_BASE:
    5442      173098 :                 scope_str = "BASE";
    5443      173098 :                 break;
    5444       78321 :         case LDB_SCOPE_ONELEVEL:
    5445       78321 :                 scope_str = "ONE";
    5446       78321 :                 break;
    5447       89575 :         case LDB_SCOPE_SUBTREE:
    5448       89575 :                 scope_str = "SUB";
    5449       89575 :                 break;
    5450           0 :         default:
    5451           0 :                 scope_str = "<Invalid scope>";
    5452           0 :                 break;
    5453             :         }
    5454      341231 :         return scope_str;
    5455             : }
    5456             : 
    5457             : 
    5458             : /*
    5459             :   search for attrs on one DN, allowing for dsdb_flags controls
    5460             :  */
    5461     2391658 : int dsdb_search_dn(struct ldb_context *ldb,
    5462             :                    TALLOC_CTX *mem_ctx,
    5463             :                    struct ldb_result **_result,
    5464             :                    struct ldb_dn *basedn,
    5465             :                    const char * const *attrs,
    5466             :                    uint32_t dsdb_flags)
    5467             : {
    5468      114952 :         int ret;
    5469      114952 :         struct ldb_request *req;
    5470      114952 :         struct ldb_result *res;
    5471     2391658 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    5472             : 
    5473     2391658 :         if (tmp_ctx == NULL) {
    5474           0 :                 return ldb_oom(ldb);
    5475             :         }
    5476             : 
    5477     2391658 :         res = talloc_zero(tmp_ctx, struct ldb_result);
    5478     2391658 :         if (!res) {
    5479           0 :                 talloc_free(tmp_ctx);
    5480           0 :                 return ldb_oom(ldb);
    5481             :         }
    5482             : 
    5483     2391658 :         ret = ldb_build_search_req(&req, ldb, res,
    5484             :                                    basedn,
    5485             :                                    LDB_SCOPE_BASE,
    5486             :                                    NULL,
    5487             :                                    attrs,
    5488             :                                    NULL,
    5489             :                                    res,
    5490             :                                    ldb_search_default_callback,
    5491             :                                    NULL);
    5492     2391658 :         if (ret != LDB_SUCCESS) {
    5493           0 :                 talloc_free(tmp_ctx);
    5494           0 :                 return ret;
    5495             :         }
    5496             : 
    5497     2391658 :         ret = dsdb_request_add_controls(req, dsdb_flags);
    5498     2391658 :         if (ret != LDB_SUCCESS) {
    5499           0 :                 talloc_free(tmp_ctx);
    5500           0 :                 return ret;
    5501             :         }
    5502             : 
    5503     2391658 :         ret = ldb_request(ldb, req);
    5504     2391658 :         if (ret == LDB_SUCCESS) {
    5505     2391658 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    5506             :         }
    5507             : 
    5508     2391658 :         talloc_free(req);
    5509     2391658 :         if (ret != LDB_SUCCESS) {
    5510      793084 :                 DBG_INFO("flags=0x%08x %s -> %s (%s)\n",
    5511             :                          dsdb_flags,
    5512             :                          basedn?ldb_dn_get_extended_linearized(tmp_ctx,
    5513             :                                                                basedn,
    5514             :                                                                1):"NULL",
    5515             :                          ldb_errstring(ldb), ldb_strerror(ret));
    5516      793084 :                 talloc_free(tmp_ctx);
    5517      793084 :                 return ret;
    5518             :         }
    5519             : 
    5520     1598574 :         DBG_DEBUG("flags=0x%08x %s -> %d\n",
    5521             :                   dsdb_flags,
    5522             :                   basedn?ldb_dn_get_extended_linearized(tmp_ctx,
    5523             :                                                         basedn,
    5524             :                                                         1):"NULL",
    5525             :                   res->count);
    5526             : 
    5527     1598574 :         *_result = talloc_steal(mem_ctx, res);
    5528             : 
    5529     1598574 :         talloc_free(tmp_ctx);
    5530     1598574 :         return LDB_SUCCESS;
    5531             : }
    5532             : 
    5533             : /*
    5534             :   search for attrs on one DN, by the GUID of the DN, allowing for
    5535             :   dsdb_flags controls
    5536             :  */
    5537        3570 : int dsdb_search_by_dn_guid(struct ldb_context *ldb,
    5538             :                            TALLOC_CTX *mem_ctx,
    5539             :                            struct ldb_result **_result,
    5540             :                            const struct GUID *guid,
    5541             :                            const char * const *attrs,
    5542             :                            uint32_t dsdb_flags)
    5543             : {
    5544        3570 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    5545           0 :         struct ldb_dn *dn;
    5546           0 :         int ret;
    5547             : 
    5548        3570 :         if (tmp_ctx == NULL) {
    5549           0 :                 return ldb_oom(ldb);
    5550             :         }
    5551             : 
    5552        3570 :         dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
    5553        3570 :         if (dn == NULL) {
    5554           0 :                 talloc_free(tmp_ctx);
    5555           0 :                 return ldb_oom(ldb);
    5556             :         }
    5557             : 
    5558        3570 :         ret = dsdb_search_dn(ldb, mem_ctx, _result, dn, attrs, dsdb_flags);
    5559        3570 :         talloc_free(tmp_ctx);
    5560        3570 :         return ret;
    5561             : }
    5562             : 
    5563          45 : NTSTATUS gmsa_system_password_update_request(
    5564             :         struct ldb_context *ldb,
    5565             :         TALLOC_CTX *mem_ctx,
    5566             :         struct ldb_dn *dn,
    5567             :         const uint8_t
    5568             :                 password_buf[static const GMSA_PASSWORD_NULL_TERMINATED_LEN],
    5569             :         struct ldb_request **request_out)
    5570             : {
    5571          45 :         DATA_BLOB password_blob = {};
    5572          45 :         struct ldb_request *request = NULL;
    5573           0 :         NTSTATUS status;
    5574           0 :         int ret;
    5575             : 
    5576          45 :         dn = ldb_dn_copy(mem_ctx, dn);
    5577          45 :         if (dn == NULL) {
    5578           0 :                 return NT_STATUS_INTERNAL_ERROR;
    5579             :         }
    5580             : 
    5581             :         /* Make a copy of the password. */
    5582          45 :         password_blob = data_blob_talloc(mem_ctx,
    5583             :                                          password_buf,
    5584             :                                          GMSA_PASSWORD_LEN);
    5585          45 :         if (password_blob.data == NULL) {
    5586           0 :                 talloc_free(dn);
    5587           0 :                 return NT_STATUS_NO_MEMORY;
    5588             :         }
    5589             : 
    5590          45 :         status = samdb_set_password_request(ldb,
    5591             :                                             mem_ctx,
    5592             :                                             dn,
    5593             :                                             &password_blob,
    5594             :                                             NULL,
    5595             :                                             DSDB_PASSWORD_RESET,
    5596             :                                             false /* reject trusts */,
    5597             :                                             &request);
    5598          45 :         if (!NT_STATUS_IS_OK(status)) {
    5599           0 :                 data_blob_free(&password_blob);
    5600           0 :                 talloc_free(dn);
    5601           0 :                 return status;
    5602             :         }
    5603             : 
    5604             :         /* Tie the lifetime of the password to that of the request. */
    5605          45 :         talloc_steal(request, password_blob.data);
    5606             : 
    5607             :         /* Tie the lifetime of the DN to that of the request. */
    5608          45 :         talloc_steal(request, dn);
    5609             : 
    5610             :         /* Make sure the password update happens as System. */
    5611          45 :         ret = dsdb_request_add_controls(request, DSDB_FLAG_AS_SYSTEM);
    5612          45 :         if (ret) {
    5613           0 :                 talloc_free(request);
    5614           0 :                 return NT_STATUS_NO_MEMORY;
    5615             :         }
    5616             : 
    5617          45 :         *request_out = request;
    5618          45 :         return NT_STATUS_OK;
    5619             : }
    5620             : 
    5621             : /*
    5622             :   general search with dsdb_flags for controls
    5623             :  */
    5624     3384738 : int dsdb_search(struct ldb_context *ldb,
    5625             :                 TALLOC_CTX *mem_ctx,
    5626             :                 struct ldb_result **_result,
    5627             :                 struct ldb_dn *basedn,
    5628             :                 enum ldb_scope scope,
    5629             :                 const char * const *attrs,
    5630             :                 uint32_t dsdb_flags,
    5631             :                 const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
    5632             : {
    5633      123122 :         int ret;
    5634      123122 :         struct ldb_request *req;
    5635      123122 :         struct ldb_result *res;
    5636      123122 :         va_list ap;
    5637     3384738 :         char *expression = NULL;
    5638     3384738 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    5639      123122 :         int tries;
    5640     3384738 :         const int max_tries = 5;
    5641             : 
    5642             :         /* cross-partitions searches with a basedn break multi-domain support */
    5643     3384738 :         SMB_ASSERT(basedn == NULL || (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) == 0);
    5644             : 
    5645     3384738 :         if (tmp_ctx == NULL) {
    5646           0 :                 return ldb_oom(ldb);
    5647             :         }
    5648             : 
    5649     3384738 :         res = talloc(tmp_ctx, struct ldb_result);
    5650     3384738 :         if (!res) {
    5651           0 :                 talloc_free(tmp_ctx);
    5652           0 :                 return ldb_oom(ldb);
    5653             :         }
    5654             : 
    5655     3384738 :         if (exp_fmt) {
    5656     3041501 :                 va_start(ap, exp_fmt);
    5657     3041501 :                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
    5658     3041501 :                 va_end(ap);
    5659             : 
    5660     3041501 :                 if (!expression) {
    5661           0 :                         talloc_free(tmp_ctx);
    5662           0 :                         return ldb_oom(ldb);
    5663             :                 }
    5664             :         }
    5665             : 
    5666     3384759 :         for (tries = 0; tries < max_tries; ++tries) {
    5667     3384759 :                 bool retry = true;
    5668             : 
    5669     3384759 :                 *res = (struct ldb_result){};
    5670             : 
    5671     3384759 :                 ret = ldb_build_search_req(&req, ldb, tmp_ctx,
    5672             :                                            basedn,
    5673             :                                            scope,
    5674             :                                            expression,
    5675             :                                            attrs,
    5676             :                                            NULL,
    5677             :                                            res,
    5678             :                                            ldb_search_default_callback,
    5679             :                                            NULL);
    5680     3384759 :                 if (ret != LDB_SUCCESS) {
    5681           0 :                         talloc_free(tmp_ctx);
    5682      257604 :                         return ret;
    5683             :                 }
    5684             : 
    5685     3384759 :                 ret = dsdb_request_add_controls(req, dsdb_flags);
    5686     3384759 :                 if (ret != LDB_SUCCESS) {
    5687           0 :                         talloc_free(tmp_ctx);
    5688           0 :                         ldb_reset_err_string(ldb);
    5689           0 :                         return ret;
    5690             :                 }
    5691             : 
    5692     3384759 :                 ret = ldb_request(ldb, req);
    5693     3384759 :                 if (ret == LDB_SUCCESS) {
    5694     3384759 :                         ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    5695             :                 }
    5696             : 
    5697     3384759 :                 if (ret != LDB_SUCCESS) {
    5698         647 :                         DBG_INFO("%s flags=0x%08x %s %s -> %s (%s)\n",
    5699             :                                  dsdb_search_scope_as_string(scope),
    5700             :                                  dsdb_flags,
    5701             :                                  basedn?ldb_dn_get_extended_linearized(tmp_ctx,
    5702             :                                                                        basedn,
    5703             :                                                                        1):"NULL",
    5704             :                                  expression?expression:"NULL",
    5705             :                                  ldb_errstring(ldb), ldb_strerror(ret));
    5706         647 :                         talloc_free(tmp_ctx);
    5707         647 :                         return ret;
    5708             :                 }
    5709             : 
    5710     3384112 :                 if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
    5711     1108311 :                         if (res->count == 0) {
    5712      256957 :                                 DBG_INFO("%s SEARCH_ONE_ONLY flags=0x%08x %s %s -> %u results\n",
    5713             :                                          dsdb_search_scope_as_string(scope),
    5714             :                                          dsdb_flags,
    5715             :                                          basedn?ldb_dn_get_extended_linearized(tmp_ctx,
    5716             :                                                                                basedn,
    5717             :                                                                                1):"NULL",
    5718             :                                          expression?expression:"NULL", res->count);
    5719      256957 :                                 talloc_free(tmp_ctx);
    5720      256957 :                                 ldb_reset_err_string(ldb);
    5721      256957 :                                 return ldb_error(ldb, LDB_ERR_NO_SUCH_OBJECT, __func__);
    5722             :                         }
    5723      851354 :                         if (res->count != 1) {
    5724           0 :                                 DBG_INFO("%s SEARCH_ONE_ONLY flags=0x%08x %s %s -> %u (expected 1) results\n",
    5725             :                                          dsdb_search_scope_as_string(scope),
    5726             :                                          dsdb_flags,
    5727             :                                          basedn?ldb_dn_get_extended_linearized(tmp_ctx,
    5728             :                                                                                basedn,
    5729             :                                                                                1):"NULL",
    5730             :                                          expression?expression:"NULL", res->count);
    5731           0 :                                 talloc_free(tmp_ctx);
    5732           0 :                                 ldb_reset_err_string(ldb);
    5733           0 :                                 return LDB_ERR_CONSTRAINT_VIOLATION;
    5734             :                         }
    5735             :                 }
    5736             : 
    5737     3127155 :                 if (!(dsdb_flags & DSDB_SEARCH_UPDATE_MANAGED_PASSWORDS)) {
    5738     3017090 :                         break;
    5739             :                 }
    5740             : 
    5741             :                 /*
    5742             :                  * If we’re searching for passwords, we must account for the
    5743             :                  * possibility that one or more of the accounts are Group
    5744             :                  * Managed Service Accounts with out‐of‐date keys. In such a
    5745             :                  * case, we must derive the new password(s), update the keys,
    5746             :                  * and perform the search again to get the updated results.
    5747             :                  *
    5748             :                  * The following attributes are necessary in order for this to
    5749             :                  * work properly:
    5750             :                  *
    5751             :                  * • msDS-ManagedPasswordId
    5752             :                  * • msDS-ManagedPasswordInterval
    5753             :                  * • objectClass
    5754             :                  * • objectSid
    5755             :                  * • whenCreated
    5756             :                  */
    5757             : 
    5758      342390 :                 ret = dsdb_update_gmsa_keys(ldb, tmp_ctx, res, &retry);
    5759      342390 :                 if (ret) {
    5760           0 :                         talloc_free(tmp_ctx);
    5761           0 :                         return ret;
    5762             :                 }
    5763      342390 :                 if (!retry) {
    5764      330165 :                         break;
    5765             :                 }
    5766             :         }
    5767     3127134 :         if (tries == max_tries) {
    5768           0 :                 talloc_free(tmp_ctx);
    5769           0 :                 ldb_reset_err_string(ldb);
    5770           0 :                 return ldb_operr(ldb);
    5771             :         }
    5772             : 
    5773     3127134 :         *_result = talloc_steal(mem_ctx, res);
    5774             : 
    5775     3127134 :         DBG_DEBUG("%s flags=0x%08x %s %s -> %d\n",
    5776             :                   dsdb_search_scope_as_string(scope),
    5777             :                   dsdb_flags,
    5778             :                   basedn?ldb_dn_get_extended_linearized(tmp_ctx,
    5779             :                                                         basedn,
    5780             :                                                         1):"NULL",
    5781             :                   expression?expression:"NULL",
    5782             :                   res->count);
    5783     3127134 :         talloc_free(tmp_ctx);
    5784     3127134 :         return LDB_SUCCESS;
    5785             : }
    5786             : 
    5787             : 
    5788             : /*
    5789             :   general search with dsdb_flags for controls
    5790             :   returns exactly 1 record or an error
    5791             :  */
    5792      813019 : int dsdb_search_one(struct ldb_context *ldb,
    5793             :                     TALLOC_CTX *mem_ctx,
    5794             :                     struct ldb_message **msg,
    5795             :                     struct ldb_dn *basedn,
    5796             :                     enum ldb_scope scope,
    5797             :                     const char * const *attrs,
    5798             :                     uint32_t dsdb_flags,
    5799             :                     const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
    5800             : {
    5801       33014 :         int ret;
    5802       33014 :         struct ldb_result *res;
    5803       33014 :         va_list ap;
    5804      813019 :         char *expression = NULL;
    5805      813019 :         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    5806             : 
    5807      813019 :         if (tmp_ctx == NULL) {
    5808           0 :                 return ldb_oom(ldb);
    5809             :         }
    5810             : 
    5811      813019 :         dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
    5812             : 
    5813      813019 :         res = talloc_zero(tmp_ctx, struct ldb_result);
    5814      813019 :         if (!res) {
    5815           0 :                 talloc_free(tmp_ctx);
    5816           0 :                 return ldb_oom(ldb);
    5817             :         }
    5818             : 
    5819      813019 :         if (exp_fmt) {
    5820      694322 :                 va_start(ap, exp_fmt);
    5821      694322 :                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
    5822      694322 :                 va_end(ap);
    5823             : 
    5824      694322 :                 if (!expression) {
    5825           0 :                         talloc_free(tmp_ctx);
    5826           0 :                         return ldb_oom(ldb);
    5827             :                 }
    5828      694322 :                 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
    5829             :                                   dsdb_flags, "%s", expression);
    5830             :         } else {
    5831      118697 :                 ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
    5832             :                                   dsdb_flags, NULL);
    5833             :         }
    5834             : 
    5835      813019 :         if (ret != LDB_SUCCESS) {
    5836      257507 :                 talloc_free(tmp_ctx);
    5837      257507 :                 return ret;
    5838             :         }
    5839             : 
    5840      555512 :         *msg = talloc_steal(mem_ctx, res->msgs[0]);
    5841      555512 :         talloc_free(tmp_ctx);
    5842             : 
    5843      555512 :         return LDB_SUCCESS;
    5844             : }
    5845             : 
    5846             : /* returns back the forest DNS name */
    5847        4855 : const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
    5848             : {
    5849        4855 :         const char *forest_name = ldb_dn_canonical_string(mem_ctx,
    5850             :                                                           ldb_get_root_basedn(ldb));
    5851          68 :         char *p;
    5852             : 
    5853        4855 :         if (forest_name == NULL) {
    5854           0 :                 return NULL;
    5855             :         }
    5856             : 
    5857        4855 :         p = strchr(forest_name, '/');
    5858        4855 :         if (p) {
    5859        4855 :                 *p = '\0';
    5860             :         }
    5861             : 
    5862        4787 :         return forest_name;
    5863             : }
    5864             : 
    5865             : /* returns back the default domain DNS name */
    5866         675 : const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
    5867             : {
    5868         675 :         const char *domain_name = ldb_dn_canonical_string(mem_ctx,
    5869             :                                                           ldb_get_default_basedn(ldb));
    5870           0 :         char *p;
    5871             : 
    5872         675 :         if (domain_name == NULL) {
    5873           0 :                 return NULL;
    5874             :         }
    5875             : 
    5876         675 :         p = strchr(domain_name, '/');
    5877         675 :         if (p) {
    5878         675 :                 *p = '\0';
    5879             :         }
    5880             : 
    5881         675 :         return domain_name;
    5882             : }
    5883             : 
    5884             : /*
    5885             :    validate that an DSA GUID belongs to the specified user sid.
    5886             :    The user SID must be a domain controller account (either RODC or
    5887             :    RWDC)
    5888             :  */
    5889        1482 : int dsdb_validate_dsa_guid(struct ldb_context *ldb,
    5890             :                            const struct GUID *dsa_guid,
    5891             :                            const struct dom_sid *sid)
    5892             : {
    5893             :         /* strategy:
    5894             :             - find DN of record with the DSA GUID in the
    5895             :               configuration partition (objectGUID)
    5896             :             - remove "NTDS Settings" component from DN
    5897             :             - do a base search on that DN for serverReference with
    5898             :               extended-dn enabled
    5899             :             - extract objectSid from resulting serverReference
    5900             :               attribute
    5901             :             - check this sid matches the sid argument
    5902             :         */
    5903           0 :         struct ldb_dn *config_dn;
    5904        1482 :         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    5905           0 :         struct ldb_message *msg;
    5906        1482 :         const char *attrs1[] = { NULL };
    5907        1482 :         const char *attrs2[] = { "serverReference", NULL };
    5908           0 :         int ret;
    5909           0 :         struct ldb_dn *dn, *account_dn;
    5910           0 :         struct dom_sid sid2;
    5911           0 :         NTSTATUS status;
    5912             : 
    5913        1482 :         if (tmp_ctx == NULL) {
    5914           0 :                 return ldb_oom(ldb);
    5915             :         }
    5916             : 
    5917        1482 :         config_dn = ldb_get_config_basedn(ldb);
    5918             : 
    5919        1482 :         ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
    5920             :                               attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
    5921        1482 :         if (ret != LDB_SUCCESS) {
    5922           0 :                 DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
    5923             :                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
    5924           0 :                 talloc_free(tmp_ctx);
    5925           0 :                 return ldb_operr(ldb);
    5926             :         }
    5927        1482 :         dn = msg->dn;
    5928             : 
    5929        1482 :         if (!ldb_dn_remove_child_components(dn, 1)) {
    5930           0 :                 talloc_free(tmp_ctx);
    5931           0 :                 return ldb_operr(ldb);
    5932             :         }
    5933             : 
    5934        1482 :         ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
    5935             :                               attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
    5936             :                               "(objectClass=server)");
    5937        1482 :         if (ret != LDB_SUCCESS) {
    5938           0 :                 DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
    5939             :                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
    5940           0 :                 talloc_free(tmp_ctx);
    5941           0 :                 return ldb_operr(ldb);
    5942             :         }
    5943             : 
    5944        1482 :         account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
    5945        1482 :         if (account_dn == NULL) {
    5946           0 :                 DEBUG(1,(__location__ ": Failed to find account dn "
    5947             :                          "(serverReference) for %s, parent of DSA with "
    5948             :                          "objectGUID %s, sid %s\n",
    5949             :                          ldb_dn_get_linearized(msg->dn),
    5950             :                          GUID_string(tmp_ctx, dsa_guid),
    5951             :                          dom_sid_string(tmp_ctx, sid)));
    5952           0 :                 talloc_free(tmp_ctx);
    5953           0 :                 return ldb_operr(ldb);
    5954             :         }
    5955             : 
    5956        1482 :         status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
    5957        1482 :         if (!NT_STATUS_IS_OK(status)) {
    5958           0 :                 DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
    5959             :                          GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
    5960           0 :                 talloc_free(tmp_ctx);
    5961           0 :                 return ldb_operr(ldb);
    5962             :         }
    5963             : 
    5964        1482 :         if (!dom_sid_equal(sid, &sid2)) {
    5965             :                 /* someone is trying to spoof another account */
    5966           0 :                 DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
    5967             :                          GUID_string(tmp_ctx, dsa_guid),
    5968             :                          dom_sid_string(tmp_ctx, sid),
    5969             :                          dom_sid_string(tmp_ctx, &sid2)));
    5970           0 :                 talloc_free(tmp_ctx);
    5971           0 :                 return ldb_operr(ldb);
    5972             :         }
    5973             : 
    5974        1482 :         talloc_free(tmp_ctx);
    5975        1482 :         return LDB_SUCCESS;
    5976             : }
    5977             : 
    5978             : static const char * const secret_attributes[] = {
    5979             :         DSDB_SECRET_ATTRIBUTES,
    5980             :         NULL
    5981             : };
    5982             : 
    5983             : /*
    5984             :   check if the attribute belongs to the RODC filtered attribute set
    5985             :   Note that attributes that are in the filtered attribute set are the
    5986             :   ones that _are_ always sent to a RODC
    5987             : */
    5988       68861 : bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
    5989             : {
    5990             :         /* they never get secret attributes */
    5991       68861 :         if (ldb_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
    5992       15349 :                 return false;
    5993             :         }
    5994             : 
    5995             :         /* they do get non-secret critical attributes */
    5996       53512 :         if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
    5997       53275 :                 return true;
    5998             :         }
    5999             : 
    6000             :         /* they do get non-secret attributes marked as being in the FAS  */
    6001         237 :         if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
    6002           0 :                 return true;
    6003             :         }
    6004             : 
    6005             :         /* other attributes are denied */
    6006         237 :         return false;
    6007             : }
    6008             : 
    6009             : /* return fsmo role dn and role owner dn for a particular role*/
    6010          56 : WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
    6011             :                                struct ldb_context *ldb,
    6012             :                                uint32_t role,
    6013             :                                struct ldb_dn **fsmo_role_dn,
    6014             :                                struct ldb_dn **role_owner_dn)
    6015             : {
    6016           0 :         int ret;
    6017          56 :         switch (role) {
    6018           4 :         case DREPL_NAMING_MASTER:
    6019           4 :                 *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
    6020           4 :                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
    6021           4 :                 if (ret != LDB_SUCCESS) {
    6022           0 :                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s\n",
    6023             :                                  ldb_errstring(ldb)));
    6024           0 :                         talloc_free(tmp_ctx);
    6025           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    6026             :                 }
    6027           4 :                 break;
    6028           4 :         case DREPL_INFRASTRUCTURE_MASTER:
    6029           4 :                 *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
    6030           4 :                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
    6031           4 :                 if (ret != LDB_SUCCESS) {
    6032           0 :                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s\n",
    6033             :                                  ldb_errstring(ldb)));
    6034           0 :                         talloc_free(tmp_ctx);
    6035           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    6036             :                 }
    6037           4 :                 break;
    6038           6 :         case DREPL_RID_MASTER:
    6039           6 :                 ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
    6040           6 :                 if (ret != LDB_SUCCESS) {
    6041           0 :                         DEBUG(0, (__location__ ": Failed to find RID Manager object - %s\n", ldb_errstring(ldb)));
    6042           0 :                         talloc_free(tmp_ctx);
    6043           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    6044             :                 }
    6045             : 
    6046           6 :                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
    6047           6 :                 if (ret != LDB_SUCCESS) {
    6048           0 :                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s\n",
    6049             :                                  ldb_errstring(ldb)));
    6050           0 :                         talloc_free(tmp_ctx);
    6051           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    6052             :                 }
    6053           6 :                 break;
    6054           4 :         case DREPL_SCHEMA_MASTER:
    6055           4 :                 *fsmo_role_dn = ldb_get_schema_basedn(ldb);
    6056           4 :                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
    6057           4 :                 if (ret != LDB_SUCCESS) {
    6058           0 :                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s\n",
    6059             :                                  ldb_errstring(ldb)));
    6060           0 :                         talloc_free(tmp_ctx);
    6061           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    6062             :                 }
    6063           4 :                 break;
    6064          38 :         case DREPL_PDC_MASTER:
    6065          38 :                 *fsmo_role_dn = ldb_get_default_basedn(ldb);
    6066          38 :                 ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
    6067          38 :                 if (ret != LDB_SUCCESS) {
    6068           0 :                         DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s\n",
    6069             :                                  ldb_errstring(ldb)));
    6070           0 :                         talloc_free(tmp_ctx);
    6071           0 :                         return WERR_DS_DRA_INTERNAL_ERROR;
    6072             :                 }
    6073          38 :                 break;
    6074           0 :         default:
    6075           0 :                 return WERR_DS_DRA_INTERNAL_ERROR;
    6076             :         }
    6077          56 :         return WERR_OK;
    6078             : }
    6079             : 
    6080          34 : const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
    6081             :                                     TALLOC_CTX *mem_ctx,
    6082             :                                     struct ldb_dn *server_dn)
    6083             : {
    6084           0 :         int ldb_ret;
    6085          34 :         struct ldb_result *res = NULL;
    6086          34 :         const char * const attrs[] = { "dNSHostName", NULL};
    6087             : 
    6088          34 :         ldb_ret = ldb_search(ldb, mem_ctx, &res,
    6089             :                              server_dn,
    6090             :                              LDB_SCOPE_BASE,
    6091             :                              attrs, NULL);
    6092          34 :         if (ldb_ret != LDB_SUCCESS) {
    6093           0 :                 DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s\n",
    6094             :                           ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
    6095           0 :                 return NULL;
    6096             :         }
    6097             : 
    6098          34 :         return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
    6099             : }
    6100             : 
    6101             : /*
    6102             :   returns true if an attribute is in the filter,
    6103             :   false otherwise, provided that attribute value is provided with the expression
    6104             : */
    6105           0 : bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
    6106             :                              const char *attr)
    6107             : {
    6108           0 :        unsigned int i;
    6109           0 :        switch (tree->operation) {
    6110           0 :        case LDB_OP_AND:
    6111             :        case LDB_OP_OR:
    6112           0 :                for (i=0;i<tree->u.list.num_elements;i++) {
    6113           0 :                        if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
    6114             :                                                        attr))
    6115           0 :                                return true;
    6116             :                }
    6117           0 :                return false;
    6118           0 :        case LDB_OP_NOT:
    6119           0 :                return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
    6120           0 :        case LDB_OP_EQUALITY:
    6121           0 :                if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
    6122           0 :                        return true;
    6123             :                }
    6124           0 :                return false;
    6125           0 :        case LDB_OP_GREATER:
    6126             :        case LDB_OP_LESS:
    6127             :        case LDB_OP_APPROX:
    6128           0 :                if (ldb_attr_cmp(tree->u.comparison.attr, attr) == 0) {
    6129           0 :                        return true;
    6130             :                }
    6131           0 :                return false;
    6132           0 :        case LDB_OP_SUBSTRING:
    6133           0 :                if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
    6134           0 :                        return true;
    6135             :                }
    6136           0 :                return false;
    6137           0 :        case LDB_OP_PRESENT:
    6138             :                /* (attrname=*) is not filtered out */
    6139           0 :                return false;
    6140           0 :        case LDB_OP_EXTENDED:
    6141           0 :                if (tree->u.extended.attr &&
    6142           0 :                    ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
    6143           0 :                        return true;
    6144             :                }
    6145           0 :                return false;
    6146             :        }
    6147           0 :        return false;
    6148             : }
    6149             : 
    6150        1571 : int dsdb_werror_at(struct ldb_context *ldb, int ldb_ecode, WERROR werr,
    6151             :                    const char *location, const char *func,
    6152             :                    const char *reason)
    6153             : {
    6154        1571 :         if (reason == NULL) {
    6155           0 :                 reason = win_errstr(werr);
    6156             :         }
    6157        1571 :         ldb_asprintf_errstring(ldb, "%08X: %s at %s:%s",
    6158             :                                W_ERROR_V(werr), reason, location, func);
    6159        1571 :         return ldb_ecode;
    6160             : }
    6161             : 
    6162             : /*
    6163             :   map an ldb error code to an approximate NTSTATUS code
    6164             :  */
    6165          43 : NTSTATUS dsdb_ldb_err_to_ntstatus(int err)
    6166             : {
    6167          43 :         switch (err) {
    6168          14 :         case LDB_SUCCESS:
    6169          43 :                 return NT_STATUS_OK;
    6170             : 
    6171           0 :         case LDB_ERR_PROTOCOL_ERROR:
    6172           0 :                 return NT_STATUS_DEVICE_PROTOCOL_ERROR;
    6173             : 
    6174           0 :         case LDB_ERR_TIME_LIMIT_EXCEEDED:
    6175           0 :                 return NT_STATUS_IO_TIMEOUT;
    6176             : 
    6177           0 :         case LDB_ERR_SIZE_LIMIT_EXCEEDED:
    6178           0 :                 return NT_STATUS_BUFFER_TOO_SMALL;
    6179             : 
    6180           0 :         case LDB_ERR_COMPARE_FALSE:
    6181             :         case LDB_ERR_COMPARE_TRUE:
    6182           0 :                 return NT_STATUS_REVISION_MISMATCH;
    6183             : 
    6184           0 :         case LDB_ERR_AUTH_METHOD_NOT_SUPPORTED:
    6185           0 :                 return NT_STATUS_NOT_SUPPORTED;
    6186             : 
    6187          20 :         case LDB_ERR_STRONG_AUTH_REQUIRED:
    6188             :         case LDB_ERR_CONFIDENTIALITY_REQUIRED:
    6189             :         case LDB_ERR_SASL_BIND_IN_PROGRESS:
    6190             :         case LDB_ERR_INAPPROPRIATE_AUTHENTICATION:
    6191             :         case LDB_ERR_INVALID_CREDENTIALS:
    6192             :         case LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS:
    6193             :         case LDB_ERR_UNWILLING_TO_PERFORM:
    6194          20 :                 return NT_STATUS_ACCESS_DENIED;
    6195             : 
    6196           9 :         case LDB_ERR_NO_SUCH_OBJECT:
    6197           9 :                 return NT_STATUS_OBJECT_NAME_NOT_FOUND;
    6198             : 
    6199           0 :         case LDB_ERR_REFERRAL:
    6200             :         case LDB_ERR_NO_SUCH_ATTRIBUTE:
    6201           0 :                 return NT_STATUS_NOT_FOUND;
    6202             : 
    6203           0 :         case LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION:
    6204           0 :                 return NT_STATUS_NOT_SUPPORTED;
    6205             : 
    6206           0 :         case LDB_ERR_ADMIN_LIMIT_EXCEEDED:
    6207           0 :                 return NT_STATUS_BUFFER_TOO_SMALL;
    6208             : 
    6209           0 :         case LDB_ERR_UNDEFINED_ATTRIBUTE_TYPE:
    6210             :         case LDB_ERR_INAPPROPRIATE_MATCHING:
    6211             :         case LDB_ERR_CONSTRAINT_VIOLATION:
    6212             :         case LDB_ERR_INVALID_ATTRIBUTE_SYNTAX:
    6213             :         case LDB_ERR_INVALID_DN_SYNTAX:
    6214             :         case LDB_ERR_NAMING_VIOLATION:
    6215             :         case LDB_ERR_OBJECT_CLASS_VIOLATION:
    6216             :         case LDB_ERR_NOT_ALLOWED_ON_NON_LEAF:
    6217             :         case LDB_ERR_NOT_ALLOWED_ON_RDN:
    6218           0 :                 return NT_STATUS_INVALID_PARAMETER;
    6219             : 
    6220           0 :         case LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS:
    6221             :         case LDB_ERR_ENTRY_ALREADY_EXISTS:
    6222           0 :                 return NT_STATUS_ERROR_DS_OBJ_STRING_NAME_EXISTS;
    6223             : 
    6224           0 :         case LDB_ERR_BUSY:
    6225           0 :                 return NT_STATUS_NETWORK_BUSY;
    6226             : 
    6227           0 :         case LDB_ERR_ALIAS_PROBLEM:
    6228             :         case LDB_ERR_ALIAS_DEREFERENCING_PROBLEM:
    6229             :         case LDB_ERR_UNAVAILABLE:
    6230             :         case LDB_ERR_LOOP_DETECT:
    6231             :         case LDB_ERR_OBJECT_CLASS_MODS_PROHIBITED:
    6232             :         case LDB_ERR_AFFECTS_MULTIPLE_DSAS:
    6233             :         case LDB_ERR_OTHER:
    6234             :         case LDB_ERR_OPERATIONS_ERROR:
    6235           0 :                 break;
    6236             :         }
    6237           0 :         return NT_STATUS_UNSUCCESSFUL;
    6238             : }
    6239             : 
    6240             : 
    6241             : /*
    6242             :   create a new naming context that will hold a partial replica
    6243             :  */
    6244           0 : int dsdb_create_partial_replica_NC(struct ldb_context *ldb,  struct ldb_dn *dn)
    6245             : {
    6246           0 :         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    6247           0 :         struct ldb_message *msg;
    6248           0 :         int ret;
    6249             : 
    6250           0 :         if (tmp_ctx == NULL) {
    6251           0 :                 return ldb_oom(ldb);
    6252             :         }
    6253             : 
    6254           0 :         msg = ldb_msg_new(tmp_ctx);
    6255           0 :         if (msg == NULL) {
    6256           0 :                 talloc_free(tmp_ctx);
    6257           0 :                 return ldb_oom(ldb);
    6258             :         }
    6259             : 
    6260           0 :         msg->dn = dn;
    6261           0 :         ret = ldb_msg_add_string(msg, "objectClass", "top");
    6262           0 :         if (ret != LDB_SUCCESS) {
    6263           0 :                 talloc_free(tmp_ctx);
    6264           0 :                 return ldb_oom(ldb);
    6265             :         }
    6266             : 
    6267             :         /* [MS-DRSR] implies that we should only add the 'top'
    6268             :          * objectclass, but that would cause lots of problems with our
    6269             :          * objectclass code as top is not structural, so we add
    6270             :          * 'domainDNS' as well to keep things sane. We're expecting
    6271             :          * this new NC to be of objectclass domainDNS after
    6272             :          * replication anyway
    6273             :          */
    6274           0 :         ret = ldb_msg_add_string(msg, "objectClass", "domainDNS");
    6275           0 :         if (ret != LDB_SUCCESS) {
    6276           0 :                 talloc_free(tmp_ctx);
    6277           0 :                 return ldb_oom(ldb);
    6278             :         }
    6279             : 
    6280           0 :         ret = ldb_msg_add_fmt(msg, "instanceType", "%u",
    6281             :                               INSTANCE_TYPE_IS_NC_HEAD|
    6282             :                               INSTANCE_TYPE_NC_ABOVE|
    6283             :                               INSTANCE_TYPE_UNINSTANT);
    6284           0 :         if (ret != LDB_SUCCESS) {
    6285           0 :                 talloc_free(tmp_ctx);
    6286           0 :                 return ldb_oom(ldb);
    6287             :         }
    6288             : 
    6289           0 :         ret = dsdb_add(ldb, msg, DSDB_MODIFY_PARTIAL_REPLICA);
    6290           0 :         if (ret != LDB_SUCCESS && ret != LDB_ERR_ENTRY_ALREADY_EXISTS) {
    6291           0 :                 DEBUG(0,("Failed to create new NC for %s - %s (%s)\n",
    6292             :                          ldb_dn_get_linearized(dn),
    6293             :                          ldb_errstring(ldb), ldb_strerror(ret)));
    6294           0 :                 talloc_free(tmp_ctx);
    6295           0 :                 return ret;
    6296             :         }
    6297             : 
    6298           0 :         DEBUG(1,("Created new NC for %s\n", ldb_dn_get_linearized(dn)));
    6299             : 
    6300           0 :         talloc_free(tmp_ctx);
    6301           0 :         return LDB_SUCCESS;
    6302             : }
    6303             : 
    6304             : /*
    6305             :  * Return the effective badPwdCount
    6306             :  *
    6307             :  * This requires that the user_msg have (if present):
    6308             :  *  - badPasswordTime
    6309             :  *  - badPwdCount
    6310             :  *
    6311             :  * This also requires that the domain_msg have (if present):
    6312             :  *  - lockOutObservationWindow
    6313             :  */
    6314       35798 : int dsdb_effective_badPwdCount(const struct ldb_message *user_msg,
    6315             :                                int64_t lockOutObservationWindow,
    6316             :                                NTTIME now)
    6317             : {
    6318        1411 :         int64_t badPasswordTime;
    6319       35798 :         badPasswordTime = ldb_msg_find_attr_as_int64(user_msg, "badPasswordTime", 0);
    6320             : 
    6321       35798 :         if (badPasswordTime - lockOutObservationWindow >= now) {
    6322        2003 :                 return ldb_msg_find_attr_as_int(user_msg, "badPwdCount", 0);
    6323             :         } else {
    6324       32384 :                 return 0;
    6325             :         }
    6326             : }
    6327             : 
    6328             : /*
    6329             :  * Returns a user's PSO, or NULL if none was found
    6330             :  */
    6331       27572 : static struct ldb_result *lookup_user_pso(struct ldb_context *sam_ldb,
    6332             :                                           TALLOC_CTX *mem_ctx,
    6333             :                                           const struct ldb_message *user_msg,
    6334             :                                           const char * const *attrs)
    6335             : {
    6336       27572 :         struct ldb_result *res = NULL;
    6337       27572 :         struct ldb_dn *pso_dn = NULL;
    6338        1410 :         int ret;
    6339             : 
    6340             :         /* if the user has a PSO that applies, then use the PSO's setting */
    6341       27572 :         pso_dn = ldb_msg_find_attr_as_dn(sam_ldb, mem_ctx, user_msg,
    6342             :                                          "msDS-ResultantPSO");
    6343             : 
    6344       27572 :         if (pso_dn != NULL) {
    6345             : 
    6346         220 :                 ret = dsdb_search_dn(sam_ldb, mem_ctx, &res, pso_dn, attrs, 0);
    6347         220 :                 if (ret != LDB_SUCCESS) {
    6348             : 
    6349             :                         /*
    6350             :                          * log the error. The caller should fallback to using
    6351             :                          * the default domain password settings
    6352             :                          */
    6353           0 :                         DBG_ERR("Error retrieving msDS-ResultantPSO %s for %s\n",
    6354             :                                 ldb_dn_get_linearized(pso_dn),
    6355             :                                 ldb_dn_get_linearized(user_msg->dn));
    6356             :                 }
    6357         220 :                 talloc_free(pso_dn);
    6358             :         }
    6359       27572 :         return res;
    6360             : }
    6361             : 
    6362             : /*
    6363             :  * Return the msDS-LockoutObservationWindow for a user message
    6364             :  *
    6365             :  * This requires that the user_msg have (if present):
    6366             :  *  - msDS-ResultantPSO
    6367             :  */
    6368       27572 : int64_t samdb_result_msds_LockoutObservationWindow(
    6369             :         struct ldb_context *sam_ldb,
    6370             :         TALLOC_CTX *mem_ctx,
    6371             :         struct ldb_dn *domain_dn,
    6372             :         const struct ldb_message *user_msg)
    6373             : {
    6374        1410 :         int64_t lockOutObservationWindow;
    6375       27572 :         struct ldb_result *res = NULL;
    6376       27572 :         const char *attrs[] = { "msDS-LockoutObservationWindow",
    6377             :                                 NULL };
    6378       27572 :         if (domain_dn == NULL) {
    6379           0 :                 smb_panic("domain dn is NULL");
    6380             :         }
    6381       27572 :         res = lookup_user_pso(sam_ldb, mem_ctx, user_msg, attrs);
    6382             : 
    6383       27572 :         if (res != NULL) {
    6384           0 :                 lockOutObservationWindow =
    6385         220 :                         ldb_msg_find_attr_as_int64(res->msgs[0],
    6386             :                                                    "msDS-LockoutObservationWindow",
    6387             :                                                     DEFAULT_OBSERVATION_WINDOW);
    6388         220 :                 talloc_free(res);
    6389             :         } else {
    6390             : 
    6391             :                 /* no PSO was found, lookup the default domain setting */
    6392        1410 :                 lockOutObservationWindow =
    6393       27352 :                          samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
    6394             :                                             "lockOutObservationWindow", NULL);
    6395             :         }
    6396       27572 :         return lockOutObservationWindow;
    6397             : }
    6398             : 
    6399             : /*
    6400             :  * Return the effective badPwdCount
    6401             :  *
    6402             :  * This requires that the user_msg have (if present):
    6403             :  *  - badPasswordTime
    6404             :  *  - badPwdCount
    6405             :  *  - msDS-ResultantPSO
    6406             :  */
    6407        4703 : int samdb_result_effective_badPwdCount(struct ldb_context *sam_ldb,
    6408             :                                        TALLOC_CTX *mem_ctx,
    6409             :                                        struct ldb_dn *domain_dn,
    6410             :                                        const struct ldb_message *user_msg)
    6411             : {
    6412        4703 :         struct timeval tv_now = timeval_current();
    6413        4703 :         NTTIME now = timeval_to_nttime(&tv_now);
    6414           0 :         int64_t lockOutObservationWindow =
    6415        4703 :                 samdb_result_msds_LockoutObservationWindow(
    6416             :                         sam_ldb, mem_ctx, domain_dn, user_msg);
    6417        4703 :         return dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
    6418             : }
    6419             : 
    6420             : /*
    6421             :  * Returns the lockoutThreshold that applies. If a PSO is specified, then that
    6422             :  * setting is used over the domain defaults
    6423             :  */
    6424        4018 : static int64_t get_lockout_threshold(struct ldb_message *domain_msg,
    6425             :                                      struct ldb_message *pso_msg)
    6426             : {
    6427        4018 :         if (pso_msg != NULL) {
    6428          40 :                 return ldb_msg_find_attr_as_int(pso_msg,
    6429             :                                                 "msDS-LockoutThreshold", 0);
    6430             :         } else {
    6431        3978 :                 return ldb_msg_find_attr_as_int(domain_msg,
    6432             :                                                 "lockoutThreshold", 0);
    6433             :         }
    6434             : }
    6435             : 
    6436             : /*
    6437             :  * Returns the lockOutObservationWindow that applies. If a PSO is specified,
    6438             :  * then that setting is used over the domain defaults
    6439             :  */
    6440         762 : static int64_t get_lockout_observation_window(struct ldb_message *domain_msg,
    6441             :                                               struct ldb_message *pso_msg)
    6442             : {
    6443         762 :         if (pso_msg != NULL) {
    6444          40 :                 return ldb_msg_find_attr_as_int64(pso_msg,
    6445             :                                                   "msDS-LockoutObservationWindow",
    6446             :                                                    DEFAULT_OBSERVATION_WINDOW);
    6447             :         } else {
    6448         722 :                 return ldb_msg_find_attr_as_int64(domain_msg,
    6449             :                                                   "lockOutObservationWindow",
    6450             :                                                    DEFAULT_OBSERVATION_WINDOW);
    6451             :         }
    6452             : }
    6453             : 
    6454             : /*
    6455             :  * Prepare an update to the badPwdCount and associated attributes.
    6456             :  *
    6457             :  * This requires that the user_msg have (if present):
    6458             :  *  - objectSid
    6459             :  *  - badPasswordTime
    6460             :  *  - badPwdCount
    6461             :  *
    6462             :  * This also requires that the domain_msg have (if present):
    6463             :  *  - pwdProperties
    6464             :  *  - lockoutThreshold
    6465             :  *  - lockOutObservationWindow
    6466             :  *
    6467             :  * This also requires that the pso_msg have (if present):
    6468             :  *  - msDS-LockoutThreshold
    6469             :  *  - msDS-LockoutObservationWindow
    6470             :  */
    6471        4018 : NTSTATUS dsdb_update_bad_pwd_count(TALLOC_CTX *mem_ctx,
    6472             :                                    struct ldb_context *sam_ctx,
    6473             :                                    struct ldb_message *user_msg,
    6474             :                                    struct ldb_message *domain_msg,
    6475             :                                    struct ldb_message *pso_msg,
    6476             :                                    struct ldb_message **_mod_msg)
    6477             : {
    6478           1 :         int ret, badPwdCount;
    6479           1 :         unsigned int i;
    6480           1 :         int64_t lockoutThreshold, lockOutObservationWindow;
    6481           1 :         struct dom_sid *sid;
    6482        4018 :         struct timeval tv_now = timeval_current();
    6483        4018 :         NTTIME now = timeval_to_nttime(&tv_now);
    6484           1 :         NTSTATUS status;
    6485        4018 :         uint32_t pwdProperties, rid = 0;
    6486           1 :         struct ldb_message *mod_msg;
    6487             : 
    6488        4018 :         sid = samdb_result_dom_sid(mem_ctx, user_msg, "objectSid");
    6489             : 
    6490        4018 :         pwdProperties = ldb_msg_find_attr_as_uint(domain_msg,
    6491             :                                                   "pwdProperties", -1);
    6492        4018 :         if (sid && !(pwdProperties & DOMAIN_PASSWORD_LOCKOUT_ADMINS)) {
    6493        4018 :                 status = dom_sid_split_rid(NULL, sid, NULL, &rid);
    6494        4018 :                 if (!NT_STATUS_IS_OK(status)) {
    6495             :                         /*
    6496             :                          * This can't happen anyway, but always try
    6497             :                          * and update the badPwdCount on failure
    6498             :                          */
    6499           0 :                         rid = 0;
    6500             :                 }
    6501             :         }
    6502        4018 :         TALLOC_FREE(sid);
    6503             : 
    6504             :         /*
    6505             :          * Work out if we are doing password lockout on the domain.
    6506             :          * Also, the built in administrator account is exempt:
    6507             :          * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375371%28v=vs.85%29.aspx
    6508             :          */
    6509        4018 :         lockoutThreshold = get_lockout_threshold(domain_msg, pso_msg);
    6510        4018 :         if (lockoutThreshold == 0 || (rid == DOMAIN_RID_ADMINISTRATOR)) {
    6511        3256 :                 DEBUG(5, ("Not updating badPwdCount on %s after wrong password\n",
    6512             :                           ldb_dn_get_linearized(user_msg->dn)));
    6513        3256 :                 return NT_STATUS_OK;
    6514             :         }
    6515             : 
    6516         762 :         mod_msg = ldb_msg_new(mem_ctx);
    6517         762 :         if (mod_msg == NULL) {
    6518           0 :                 return NT_STATUS_NO_MEMORY;
    6519             :         }
    6520         762 :         mod_msg->dn = ldb_dn_copy(mod_msg, user_msg->dn);
    6521         762 :         if (mod_msg->dn == NULL) {
    6522           0 :                 TALLOC_FREE(mod_msg);
    6523           0 :                 return NT_STATUS_NO_MEMORY;
    6524             :         }
    6525             : 
    6526         762 :         lockOutObservationWindow = get_lockout_observation_window(domain_msg,
    6527             :                                                                   pso_msg);
    6528             : 
    6529         762 :         badPwdCount = dsdb_effective_badPwdCount(user_msg, lockOutObservationWindow, now);
    6530             : 
    6531         762 :         badPwdCount++;
    6532             : 
    6533         762 :         ret = samdb_msg_add_int(sam_ctx, mod_msg, mod_msg, "badPwdCount", badPwdCount);
    6534         762 :         if (ret != LDB_SUCCESS) {
    6535           0 :                 TALLOC_FREE(mod_msg);
    6536           0 :                 return NT_STATUS_NO_MEMORY;
    6537             :         }
    6538         762 :         ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "badPasswordTime", now);
    6539         762 :         if (ret != LDB_SUCCESS) {
    6540           0 :                 TALLOC_FREE(mod_msg);
    6541           0 :                 return NT_STATUS_NO_MEMORY;
    6542             :         }
    6543             : 
    6544         762 :         if (dsdb_account_is_trust(user_msg)) {
    6545             :                 /* Trust accounts cannot be locked out. */
    6546         750 :         } else if (badPwdCount >= lockoutThreshold) {
    6547         110 :                 ret = samdb_msg_add_int64(sam_ctx, mod_msg, mod_msg, "lockoutTime", now);
    6548         110 :                 if (ret != LDB_SUCCESS) {
    6549           0 :                         TALLOC_FREE(mod_msg);
    6550           0 :                         return NT_STATUS_NO_MEMORY;
    6551             :                 }
    6552         110 :                 DEBUGC( DBGC_AUTH, 1, ("Locked out user %s after %d wrong passwords\n",
    6553             :                           ldb_dn_get_linearized(user_msg->dn), badPwdCount));
    6554             :         } else {
    6555         640 :                 DEBUGC( DBGC_AUTH, 5, ("Updated badPwdCount on %s after %d wrong passwords\n",
    6556             :                           ldb_dn_get_linearized(user_msg->dn), badPwdCount));
    6557             :         }
    6558             : 
    6559             :         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
    6560        2396 :         for (i=0; i< mod_msg->num_elements; i++) {
    6561        1634 :                 mod_msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
    6562             :         }
    6563             : 
    6564         762 :         *_mod_msg = mod_msg;
    6565         762 :         return NT_STATUS_OK;
    6566             : }
    6567             : 
    6568             : /**
    6569             :  * Sets defaults for a User object
    6570             :  * List of default attributes set:
    6571             :  *      accountExpires, badPasswordTime, badPwdCount,
    6572             :  *      codePage, countryCode, lastLogoff, lastLogon
    6573             :  *      logonCount, pwdLastSet
    6574             :  */
    6575       30459 : int dsdb_user_obj_set_defaults(struct ldb_context *ldb,
    6576             :                                struct ldb_message *usr_obj,
    6577             :                                struct ldb_request *req)
    6578             : {
    6579         221 :         size_t i;
    6580         221 :         int ret;
    6581         221 :         static const struct attribute_values {
    6582             :                 const char *name;
    6583             :                 const char *value;
    6584             :                 const char *add_value;
    6585             :                 const char *mod_value;
    6586             :                 const char *control;
    6587             :                 unsigned add_flags;
    6588             :                 unsigned mod_flags;
    6589             :         } map[] = {
    6590             :                 {
    6591             :                         .name = "accountExpires",
    6592             :                         .add_value = "9223372036854775807",
    6593             :                         .mod_value = "0",
    6594             :                 },
    6595             :                 {
    6596             :                         .name = "badPasswordTime",
    6597             :                         .value = "0"
    6598             :                 },
    6599             :                 {
    6600             :                         .name = "badPwdCount",
    6601             :                         .value = "0"
    6602             :                 },
    6603             :                 {
    6604             :                         .name = "codePage",
    6605             :                         .value = "0"
    6606             :                 },
    6607             :                 {
    6608             :                         .name = "countryCode",
    6609             :                         .value = "0"
    6610             :                 },
    6611             :                 {
    6612             :                         .name = "lastLogoff",
    6613             :                         .value = "0"
    6614             :                 },
    6615             :                 {
    6616             :                         .name = "lastLogon",
    6617             :                         .value = "0"
    6618             :                 },
    6619             :                 {
    6620             :                         .name = "logonCount",
    6621             :                         .value = "0"
    6622             :                 },
    6623             :                 {
    6624             :                         .name = "logonHours",
    6625             :                         .add_flags = DSDB_FLAG_INTERNAL_FORCE_META_DATA,
    6626             :                 },
    6627             :                 {
    6628             :                         .name = "pwdLastSet",
    6629             :                         .value = "0",
    6630             :                         .control = DSDB_CONTROL_PASSWORD_DEFAULT_LAST_SET_OID,
    6631             :                 },
    6632             :                 {
    6633             :                         .name = "adminCount",
    6634             :                         .mod_value = "0",
    6635             :                 },
    6636             :                 {
    6637             :                         .name = "operatorCount",
    6638             :                         .mod_value = "0",
    6639             :                 },
    6640             :         };
    6641             : 
    6642      395967 :         for (i = 0; i < ARRAY_SIZE(map); i++) {
    6643      365508 :                 bool added = false;
    6644      365508 :                 const char *value = NULL;
    6645      365508 :                 unsigned flags = 0;
    6646             : 
    6647      365508 :                 if (req != NULL && req->operation == LDB_ADD) {
    6648      364788 :                         value = map[i].add_value;
    6649      364788 :                         flags = map[i].add_flags;
    6650             :                 } else {
    6651         720 :                         value = map[i].mod_value;
    6652         720 :                         flags = map[i].mod_flags;
    6653             :                 }
    6654             : 
    6655      365508 :                 if (value == NULL) {
    6656      334929 :                         value = map[i].value;
    6657             :                 }
    6658             : 
    6659      365508 :                 if (value != NULL) {
    6660      274251 :                         flags |= LDB_FLAG_MOD_ADD;
    6661             :                 }
    6662             : 
    6663      365508 :                 if (flags == 0) {
    6664       60858 :                         continue;
    6665             :                 }
    6666             : 
    6667      306860 :                 ret = samdb_find_or_add_attribute_ex(ldb, usr_obj,
    6668      304650 :                                                      map[i].name,
    6669             :                                                      value, flags,
    6670             :                                                      &added);
    6671      304650 :                 if (ret != LDB_SUCCESS) {
    6672           0 :                         return ret;
    6673             :                 }
    6674             : 
    6675      304650 :                 if (req != NULL && added && map[i].control != NULL) {
    6676       30442 :                         ret = ldb_request_add_control(req,
    6677       30221 :                                                       map[i].control,
    6678             :                                                       false, NULL);
    6679       30442 :                         if (ret != LDB_SUCCESS) {
    6680           0 :                                 return ret;
    6681             :                         }
    6682             :                 }
    6683             :         }
    6684             : 
    6685       30238 :         return LDB_SUCCESS;
    6686             : }
    6687             : 
    6688             : /**
    6689             :  * Sets 'sAMAccountType on user object based on userAccountControl.
    6690             :  * This function is used in processing both 'add' and 'modify' requests.
    6691             :  * @param ldb Current ldb_context
    6692             :  * @param usr_obj ldb_message representing User object
    6693             :  * @param user_account_control Value for userAccountControl flags
    6694             :  * @param account_type_p Optional pointer to account_type to return
    6695             :  * @return LDB_SUCCESS or LDB_ERR* code on failure
    6696             :  */
    6697       30350 : int dsdb_user_obj_set_account_type(struct ldb_context *ldb, struct ldb_message *usr_obj,
    6698             :                                    uint32_t user_account_control, uint32_t *account_type_p)
    6699             : {
    6700         221 :         int ret;
    6701         221 :         uint32_t account_type;
    6702             : 
    6703       30350 :         account_type = ds_uf2atype(user_account_control);
    6704       30350 :         if (account_type == 0) {
    6705           0 :                 ldb_set_errstring(ldb, "dsdb: Unrecognized account type!");
    6706           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    6707             :         }
    6708       30350 :         ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj,
    6709             :                                        "sAMAccountType",
    6710             :                                        account_type,
    6711             :                                        LDB_FLAG_MOD_REPLACE);
    6712       30350 :         if (ret != LDB_SUCCESS) {
    6713           0 :                 return ret;
    6714             :         }
    6715             : 
    6716       30350 :         if (account_type_p) {
    6717           0 :                 *account_type_p = account_type;
    6718             :         }
    6719             : 
    6720       30129 :         return LDB_SUCCESS;
    6721             : }
    6722             : 
    6723             : /**
    6724             :  * Determine and set primaryGroupID based on userAccountControl value.
    6725             :  * This function is used in processing both 'add' and 'modify' requests.
    6726             :  * @param ldb Current ldb_context
    6727             :  * @param usr_obj ldb_message representing User object
    6728             :  * @param user_account_control Value for userAccountControl flags
    6729             :  * @param group_rid_p Optional pointer to group RID to return
    6730             :  * @return LDB_SUCCESS or LDB_ERR* code on failure
    6731             :  */
    6732       30222 : int dsdb_user_obj_set_primary_group_id(struct ldb_context *ldb, struct ldb_message *usr_obj,
    6733             :                                        uint32_t user_account_control, uint32_t *group_rid_p)
    6734             : {
    6735         199 :         int ret;
    6736         199 :         uint32_t rid;
    6737             : 
    6738       30222 :         rid = ds_uf2prim_group_rid(user_account_control);
    6739             : 
    6740       30222 :         ret = samdb_msg_add_uint_flags(ldb, usr_obj, usr_obj,
    6741             :                                        "primaryGroupID", rid,
    6742             :                                        LDB_FLAG_MOD_REPLACE);
    6743       30222 :         if (ret != LDB_SUCCESS) {
    6744           0 :                 return ret;
    6745             :         }
    6746             : 
    6747       30222 :         if (group_rid_p) {
    6748       30222 :                 *group_rid_p = rid;
    6749             :         }
    6750             : 
    6751       30023 :         return LDB_SUCCESS;
    6752             : }
    6753             : 
    6754             : /**
    6755             :  * Returns True if the source and target DNs both have the same naming context,
    6756             :  * i.e. they're both in the same partition.
    6757             :  */
    6758        3720 : bool dsdb_objects_have_same_nc(struct ldb_context *ldb,
    6759             :                                TALLOC_CTX *mem_ctx,
    6760             :                                struct ldb_dn *source_dn,
    6761             :                                struct ldb_dn *target_dn)
    6762             : {
    6763           0 :         TALLOC_CTX *tmp_ctx;
    6764        3720 :         struct ldb_dn *source_nc = NULL;
    6765        3720 :         struct ldb_dn *target_nc = NULL;
    6766           0 :         int ret;
    6767        3720 :         bool same_nc = true;
    6768             : 
    6769        3720 :         tmp_ctx = talloc_new(mem_ctx);
    6770        3720 :         if (tmp_ctx == NULL) {
    6771           0 :                 return ldb_oom(ldb);
    6772             :         }
    6773             : 
    6774        3720 :         ret = dsdb_find_nc_root(ldb, tmp_ctx, source_dn, &source_nc);
    6775             :         /* fix clang warning */
    6776        3720 :         if (source_nc == NULL) {
    6777           0 :                 ret = LDB_ERR_OTHER;
    6778             :         }
    6779        3720 :         if (ret != LDB_SUCCESS) {
    6780           0 :                 DBG_ERR("Failed to find base DN for source %s: %s\n",
    6781             :                         ldb_dn_get_linearized(source_dn), ldb_errstring(ldb));
    6782           0 :                 talloc_free(tmp_ctx);
    6783           0 :                 return true;
    6784             :         }
    6785             : 
    6786        3720 :         ret = dsdb_find_nc_root(ldb, tmp_ctx, target_dn, &target_nc);
    6787             :         /* fix clang warning */
    6788        3720 :         if (target_nc == NULL) {
    6789           0 :                 ret = LDB_ERR_OTHER;
    6790             :         }
    6791        3720 :         if (ret != LDB_SUCCESS) {
    6792           0 :                 DBG_ERR("Failed to find base DN for target %s: %s\n",
    6793             :                         ldb_dn_get_linearized(target_dn), ldb_errstring(ldb));
    6794           0 :                 talloc_free(tmp_ctx);
    6795           0 :                 return true;
    6796             :         }
    6797             : 
    6798        3720 :         same_nc = (ldb_dn_compare(source_nc, target_nc) == 0);
    6799             : 
    6800        3720 :         talloc_free(tmp_ctx);
    6801             : 
    6802        3720 :         return same_nc;
    6803             : }
    6804             : /*
    6805             :  * Context for dsdb_count_domain_callback
    6806             :  */
    6807             : struct dsdb_count_domain_context {
    6808             :         /*
    6809             :          * Number of matching records
    6810             :          */
    6811             :         size_t count;
    6812             :         /*
    6813             :          * sid of the domain that the records must belong to.
    6814             :          * if NULL records can belong to any domain.
    6815             :          */
    6816             :         struct dom_sid *dom_sid;
    6817             : };
    6818             : 
    6819             : /*
    6820             :  * @brief ldb async callback for dsdb_domain_count.
    6821             :  *
    6822             :  * count the number of records in the database matching an LDAP query,
    6823             :  * optionally filtering for domain membership.
    6824             :  *
    6825             :  * @param [in,out] req the ldb request being processed
    6826             :  *                    req->context contains:
    6827             :  *                        count   The number of matching records
    6828             :  *                        dom_sid The domain sid, if present records must belong
    6829             :  *                                to the domain to be counted.
    6830             :  *@param [in,out] ares The query result.
    6831             :  *
    6832             :  * @return an LDB error code
    6833             :  *
    6834             :  */
    6835       11307 : static int dsdb_count_domain_callback(
    6836             :         struct ldb_request *req,
    6837             :         struct ldb_reply *ares)
    6838             : {
    6839             : 
    6840       11307 :         if (ares == NULL) {
    6841           0 :                 return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
    6842             :         }
    6843       11307 :         if (ares->error != LDB_SUCCESS) {
    6844           0 :                 int error = ares->error;
    6845           0 :                 TALLOC_FREE(ares);
    6846           0 :                 return ldb_request_done(req, error);
    6847             :         }
    6848             : 
    6849       11307 :         switch (ares->type) {
    6850        7231 :         case LDB_REPLY_ENTRY:
    6851             :         {
    6852        7231 :                 struct dsdb_count_domain_context *context = NULL;
    6853          96 :                 ssize_t ret;
    6854          96 :                 bool in_domain;
    6855          96 :                 struct dom_sid sid;
    6856          96 :                 const struct ldb_val *v;
    6857             : 
    6858        7231 :                 context = req->context;
    6859        7231 :                 if (context->dom_sid == NULL) {
    6860        5001 :                         context->count++;
    6861        5001 :                         break;
    6862             :                 }
    6863             : 
    6864        2230 :                 v = ldb_msg_find_ldb_val(ares->message, "objectSid");
    6865        2230 :                 if (v == NULL) {
    6866           0 :                         break;
    6867             :                 }
    6868             : 
    6869        2230 :                 ret = sid_parse(v->data, v->length, &sid);
    6870        2230 :                 if (ret == -1) {
    6871           0 :                         break;
    6872             :                 }
    6873             : 
    6874        2230 :                 in_domain = dom_sid_in_domain(context->dom_sid, &sid);
    6875        2230 :                 if (!in_domain) {
    6876        1092 :                         break;
    6877             :                 }
    6878             : 
    6879        1138 :                 context->count++;
    6880        1138 :                 break;
    6881             :         }
    6882         336 :         case LDB_REPLY_REFERRAL:
    6883         336 :                 break;
    6884             : 
    6885        3644 :         case LDB_REPLY_DONE:
    6886        3740 :                 TALLOC_FREE(ares);
    6887        3740 :                 return ldb_request_done(req, LDB_SUCCESS);
    6888             :         }
    6889             : 
    6890        7567 :         TALLOC_FREE(ares);
    6891             : 
    6892        7567 :         return LDB_SUCCESS;
    6893             : }
    6894             : 
    6895             : /*
    6896             :  * @brief Count the number of records matching a query.
    6897             :  *
    6898             :  * Count the number of entries in the database matching the supplied query,
    6899             :  * optionally filtering only those entries belonging to the supplied domain.
    6900             :  *
    6901             :  * @param ldb [in] Current ldb context
    6902             :  * @param count [out] Pointer to the count
    6903             :  * @param base [in] The base dn for the query
    6904             :  * @param dom_sid [in] The domain sid, if non NULL records that are not a member
    6905             :  *                     of the domain are ignored.
    6906             :  * @param scope [in] Search scope.
    6907             :  * @param exp_fmt [in] format string for the query.
    6908             :  *
    6909             :  * @return LDB_STATUS code.
    6910             :  */
    6911        3740 : int PRINTF_ATTRIBUTE(6, 7) dsdb_domain_count(
    6912             :         struct ldb_context *ldb,
    6913             :         size_t *count,
    6914             :         struct ldb_dn *base,
    6915             :         struct dom_sid *dom_sid,
    6916             :         enum ldb_scope scope,
    6917             :         const char *exp_fmt, ...)
    6918             : {
    6919        3740 :         TALLOC_CTX *tmp_ctx = NULL;
    6920        3740 :         struct ldb_request *req = NULL;
    6921        3740 :         struct dsdb_count_domain_context *context = NULL;
    6922        3740 :         char *expression = NULL;
    6923        3740 :         const char *object_sid[] = {"objectSid", NULL};
    6924        3740 :         const char *none[] = {NULL};
    6925          96 :         va_list ap;
    6926          96 :         int ret;
    6927             : 
    6928        3740 :         *count = 0;
    6929        3740 :         tmp_ctx = talloc_new(ldb);
    6930        3740 :         if (tmp_ctx == NULL) {
    6931           0 :                 return ldb_oom(ldb);
    6932             :         }
    6933             : 
    6934        3740 :         context = talloc_zero(tmp_ctx, struct dsdb_count_domain_context);
    6935        3740 :         if (context == NULL) {
    6936           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    6937             :         }
    6938        3740 :         context->dom_sid = dom_sid;
    6939             : 
    6940        3740 :         if (exp_fmt) {
    6941        3740 :                 va_start(ap, exp_fmt);
    6942        3740 :                 expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
    6943        3740 :                 va_end(ap);
    6944             : 
    6945        3740 :                 if (expression == NULL) {
    6946           0 :                         TALLOC_FREE(context);
    6947           0 :                         TALLOC_FREE(tmp_ctx);
    6948           0 :                         return LDB_ERR_OPERATIONS_ERROR;
    6949             :                 }
    6950             :         }
    6951             : 
    6952        3740 :         ret = ldb_build_search_req(
    6953             :                 &req,
    6954             :                 ldb,
    6955             :                 tmp_ctx,
    6956             :                 base,
    6957             :                 scope,
    6958             :                 expression,
    6959             :                 (dom_sid == NULL) ? none : object_sid,
    6960             :                 NULL,
    6961             :                 context,
    6962             :                 dsdb_count_domain_callback,
    6963             :                 NULL);
    6964        3740 :         ldb_req_set_location(req, "dsdb_domain_count");
    6965             : 
    6966        3740 :         if (ret != LDB_SUCCESS) goto done;
    6967             : 
    6968        3740 :         ret = ldb_request(ldb, req);
    6969             : 
    6970        3740 :         if (ret == LDB_SUCCESS) {
    6971        3740 :                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    6972        3740 :                 if (ret == LDB_SUCCESS) {
    6973        3740 :                         *count = context->count;
    6974             :                 }
    6975             :         }
    6976             : 
    6977             : 
    6978           0 : done:
    6979        3740 :         TALLOC_FREE(expression);
    6980        3740 :         TALLOC_FREE(req);
    6981        3740 :         TALLOC_FREE(context);
    6982        3740 :         TALLOC_FREE(tmp_ctx);
    6983             : 
    6984        3740 :         return ret;
    6985             : }
    6986             : 
    6987             : /*
    6988             :  * Returns 1 if 'sids' contains the Protected Users group SID for the domain, 0
    6989             :  * if not. Returns a negative value on error.
    6990             :  */
    6991       77905 : int dsdb_is_protected_user(struct ldb_context *ldb,
    6992             :                            const struct auth_SidAttr *sids,
    6993             :                            uint32_t num_sids)
    6994             : {
    6995       77905 :         const struct dom_sid *domain_sid = NULL;
    6996        3187 :         struct dom_sid protected_users_sid;
    6997        3187 :         uint32_t i;
    6998             : 
    6999       77905 :         domain_sid = samdb_domain_sid(ldb);
    7000       77905 :         if (domain_sid == NULL) {
    7001           0 :                 return -1;
    7002             :         }
    7003             : 
    7004       77905 :         protected_users_sid = *domain_sid;
    7005       77905 :         if (!sid_append_rid(&protected_users_sid, DOMAIN_RID_PROTECTED_USERS)) {
    7006           0 :                 return -1;
    7007             :         }
    7008             : 
    7009      564036 :         for (i = 0; i < num_sids; ++i) {
    7010      486205 :                 if (dom_sid_equal(&protected_users_sid, &sids[i].sid)) {
    7011          74 :                         return 1;
    7012             :                 }
    7013             :         }
    7014             : 
    7015       74644 :         return 0;
    7016             : }
    7017             : 
    7018      427105 : bool dsdb_account_is_trust(const struct ldb_message *msg)
    7019             : {
    7020       13479 :         uint32_t userAccountControl;
    7021             : 
    7022      427105 :         userAccountControl = ldb_msg_find_attr_as_uint(msg,
    7023             :                                                        "userAccountControl",
    7024             :                                                        0);
    7025      427105 :         return userAccountControl & UF_TRUST_ACCOUNT_MASK;
    7026             : }

Generated by: LCOV version 1.14