LCOV - code coverage report
Current view: top level - source4/dsdb/common - util.c (source / functions) Hit Total Coverage
Test: coverage report for v4-17-test 1498b464 Lines: 1838 2675 68.7 %
Date: 2024-06-13 04:01:37 Functions: 162 174 93.1 %

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

Generated by: LCOV version 1.13