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

Generated by: LCOV version 1.14