LCOV - code coverage report
Current view: top level - source4/dsdb/common - util.c (source / functions) Hit Total Coverage
Test: coverage report for master 6248eab5 Lines: 1734 2504 69.2 %
Date: 2021-08-25 13:27:56 Functions: 149 159 93.7 %

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

Generated by: LCOV version 1.13