LCOV - code coverage report
Current view: top level - source4/dsdb/common - util.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 2176 3238 67.2 %
Date: 2024-02-28 12:06:22 Functions: 167 182 91.8 %

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

Generated by: LCOV version 1.14