LCOV - code coverage report
Current view: top level - source4/dsdb/samdb/ldb_modules - samldb.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 2289 2754 83.1 %
Date: 2024-04-13 12:30:31 Functions: 77 77 100.0 %

          Line data    Source code
       1             : /*
       2             :    SAM ldb module
       3             : 
       4             :    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005-2014
       5             :    Copyright (C) Simo Sorce  2004-2008
       6             :    Copyright (C) Matthias Dieter Wallnöfer 2009-2011
       7             :    Copyright (C) Matthieu Patou 2012
       8             :    Copyright (C) Catalyst.Net Ltd 2017
       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             : /*
      25             :  *  Name: ldb
      26             :  *
      27             :  *  Component: ldb samldb module
      28             :  *
      29             :  *  Description: various internal DSDB triggers - most for SAM specific objects
      30             :  *
      31             :  *  Author: Simo Sorce
      32             :  */
      33             : 
      34             : #include "includes.h"
      35             : #include "libcli/ldap/ldap_ndr.h"
      36             : #include "ldb_module.h"
      37             : #include "auth/auth.h"
      38             : #include "dsdb/samdb/samdb.h"
      39             : #include "dsdb/samdb/ldb_modules/util.h"
      40             : #include "dsdb/samdb/ldb_modules/ridalloc.h"
      41             : #include "libcli/security/security.h"
      42             : #include "librpc/gen_ndr/ndr_security.h"
      43             : #include "ldb_wrap.h"
      44             : #include "param/param.h"
      45             : #include "libds/common/flag_mapping.h"
      46             : #include "system/network.h"
      47             : #include "librpc/gen_ndr/irpc.h"
      48             : #include "lib/util/smb_strtox.h"
      49             : 
      50             : #undef strcasecmp
      51             : 
      52             : struct samldb_ctx;
      53             : enum samldb_add_type {
      54             :         SAMLDB_TYPE_USER,
      55             :         SAMLDB_TYPE_GROUP,
      56             :         SAMLDB_TYPE_CLASS,
      57             :         SAMLDB_TYPE_ATTRIBUTE
      58             : };
      59             : 
      60             : typedef int (*samldb_step_fn_t)(struct samldb_ctx *);
      61             : 
      62             : struct samldb_step {
      63             :         struct samldb_step *next;
      64             :         samldb_step_fn_t fn;
      65             : };
      66             : 
      67             : struct samldb_ctx {
      68             :         struct ldb_module *module;
      69             :         struct ldb_request *req;
      70             : 
      71             :         /* used for add operations */
      72             :         enum samldb_add_type type;
      73             : 
      74             :         /*
      75             :          * should we apply the need_trailing_dollar restriction to
      76             :          * samAccountName
      77             :          */
      78             : 
      79             :         bool need_trailing_dollar;
      80             : 
      81             :         /* the resulting message */
      82             :         struct ldb_message *msg;
      83             : 
      84             :         /* used in "samldb_find_for_defaultObjectCategory" */
      85             :         struct ldb_dn *dn, *res_dn;
      86             : 
      87             :         /* all the async steps necessary to complete the operation */
      88             :         struct samldb_step *steps;
      89             :         struct samldb_step *curstep;
      90             : 
      91             :         /* If someone set an ares to forward controls and response back to the caller */
      92             :         struct ldb_reply *ares;
      93             : };
      94             : 
      95     1205517 : static struct samldb_ctx *samldb_ctx_init(struct ldb_module *module,
      96             :                                           struct ldb_request *req)
      97             : {
      98      105289 :         struct ldb_context *ldb;
      99      105289 :         struct samldb_ctx *ac;
     100             : 
     101     1205517 :         ldb = ldb_module_get_ctx(module);
     102             : 
     103     1205517 :         ac = talloc_zero(req, struct samldb_ctx);
     104     1205517 :         if (ac == NULL) {
     105           0 :                 ldb_oom(ldb);
     106           0 :                 return NULL;
     107             :         }
     108             : 
     109     1205517 :         ac->module = module;
     110     1205517 :         ac->req = req;
     111             : 
     112     1205517 :         return ac;
     113             : }
     114             : 
     115      366670 : static int samldb_add_step(struct samldb_ctx *ac, samldb_step_fn_t fn)
     116             : {
     117       47778 :         struct samldb_step *step, *stepper;
     118             : 
     119      366670 :         step = talloc_zero(ac, struct samldb_step);
     120      366670 :         if (step == NULL) {
     121           0 :                 return ldb_oom(ldb_module_get_ctx(ac->module));
     122             :         }
     123             : 
     124      366670 :         step->fn = fn;
     125             : 
     126      366670 :         if (ac->steps == NULL) {
     127      260661 :                 ac->steps = step;
     128      260661 :                 ac->curstep = step;
     129             :         } else {
     130      106009 :                 if (ac->curstep == NULL)
     131           0 :                         return ldb_operr(ldb_module_get_ctx(ac->module));
     132      139729 :                 for (stepper = ac->curstep; stepper->next != NULL;
     133       33548 :                         stepper = stepper->next);
     134      106009 :                 stepper->next = step;
     135             :         }
     136             : 
     137      318892 :         return LDB_SUCCESS;
     138             : }
     139             : 
     140      260546 : static int samldb_first_step(struct samldb_ctx *ac)
     141             : {
     142      260546 :         if (ac->steps == NULL) {
     143           0 :                 return ldb_operr(ldb_module_get_ctx(ac->module));
     144             :         }
     145             : 
     146      260546 :         ac->curstep = ac->steps;
     147      260546 :         return ac->curstep->fn(ac);
     148             : }
     149             : 
     150      366315 : static int samldb_next_step(struct samldb_ctx *ac)
     151             : {
     152      366315 :         if (ac->curstep->next) {
     153      105969 :                 ac->curstep = ac->curstep->next;
     154      105969 :                 return ac->curstep->fn(ac);
     155             :         }
     156             : 
     157             :         /* We exit the samldb module here. If someone set an "ares" to forward
     158             :          * controls and response back to the caller, use them. */
     159      260346 :         if (ac->ares) {
     160      260346 :                 return ldb_module_done(ac->req, ac->ares->controls,
     161      219725 :                                        ac->ares->response, LDB_SUCCESS);
     162             :         } else {
     163           0 :                 return ldb_module_done(ac->req, NULL, NULL, LDB_SUCCESS);
     164             :         }
     165             : }
     166             : 
     167      339686 : static int samldb_get_single_valued_attr(struct ldb_context *ldb,
     168             :                                          struct samldb_ctx *ac,
     169             :                                          const char *attr,
     170             :                                          const char **value)
     171             : {
     172             :         /*
     173             :          * The steps we end up going through to get and check a single valued
     174             :          * attribute.
     175             :          */
     176      339686 :         struct ldb_message_element *el = NULL;
     177       42140 :         int ret;
     178             : 
     179      339686 :         *value = NULL;
     180             : 
     181      381826 :         ret = dsdb_get_expected_new_values(ac,
     182      339686 :                                            ac->msg,
     183             :                                            attr,
     184             :                                            &el,
     185      339686 :                                            ac->req->operation);
     186             : 
     187      339686 :         if (ret != LDB_SUCCESS) {
     188           0 :                 return ret;
     189             :         }
     190      339686 :         if (el == NULL) {
     191             :                 /* we are not affected */
     192       25986 :                 return LDB_SUCCESS;
     193             :         }
     194             : 
     195      312643 :         if (el->num_values > 1) {
     196           2 :                 ldb_asprintf_errstring(
     197             :                         ldb,
     198             :                         "samldb: %s has %u values, should be single-valued!",
     199           2 :                         attr, el->num_values);
     200           2 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
     201      312641 :         } else if (el->num_values == 0) {
     202           9 :                 ldb_asprintf_errstring(
     203             :                         ldb,
     204             :                         "samldb: new value for %s "
     205             :                         "not provided for mandatory, single-valued attribute!",
     206             :                         attr);
     207           9 :                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
     208             :         }
     209             : 
     210             : 
     211      312632 :         if (el->values[0].length == 0) {
     212           0 :                 ldb_asprintf_errstring(
     213             :                         ldb,
     214             :                         "samldb: %s is of zero length, should have a value!",
     215             :                         attr);
     216           0 :                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
     217             :         }
     218             : 
     219      312632 :         *value = (char *)el->values[0].data;
     220             : 
     221      312632 :         return LDB_SUCCESS;
     222             : }
     223             : 
     224      259718 : static int samldb_unique_attr_check(struct samldb_ctx *ac, const char *attr,
     225             :                                     const char *attr_conflict,
     226             :                                     struct ldb_dn *base_dn)
     227             : {
     228      259718 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     229      259718 :         const char * const no_attrs[] = { NULL };
     230      259718 :         struct ldb_result *res = NULL;
     231      259718 :         const char *str = NULL;
     232      259718 :         const char *enc_str = NULL;
     233       39972 :         int ret;
     234             : 
     235      259718 :         ret = samldb_get_single_valued_attr(ldb, ac, attr, &str);
     236      259718 :         if (ret != LDB_SUCCESS) {
     237          11 :                 return ret;
     238             :         }
     239      259707 :         if (str == NULL) {
     240             :                 /* the attribute wasn't found */
     241         734 :                 return LDB_SUCCESS;
     242             :         }
     243             : 
     244      258973 :         enc_str = ldb_binary_encode_string(ac, str);
     245      258973 :         if (enc_str == NULL) {
     246           0 :                 return ldb_module_oom(ac->module);
     247             :         }
     248             : 
     249             :         /*
     250             :          * No other object should have the attribute with this value.
     251             :          */
     252      258973 :         if (attr_conflict != NULL) {
     253        1905 :                 ret = dsdb_module_search(ac->module, ac, &res,
     254             :                                          base_dn,
     255             :                                          LDB_SCOPE_SUBTREE, no_attrs,
     256             :                                          DSDB_FLAG_NEXT_MODULE, ac->req,
     257             :                                          "(|(%s=%s)(%s=%s))",
     258             :                                          attr, enc_str,
     259             :                                          attr_conflict, enc_str);
     260             :         } else {
     261      257068 :                 ret = dsdb_module_search(ac->module, ac, &res,
     262             :                                          base_dn,
     263             :                                          LDB_SCOPE_SUBTREE, no_attrs,
     264             :                                          DSDB_FLAG_NEXT_MODULE, ac->req,
     265             :                                          "(%s=%s)", attr, enc_str);
     266             :         }
     267      258973 :         if (ret != LDB_SUCCESS) {
     268           0 :                 return ret;
     269             :         }
     270      258973 :         if (res->count > 1) {
     271           0 :                 return ldb_operr(ldb);
     272      258973 :         } else if (res->count == 1) {
     273         568 :                 if (ldb_dn_compare(res->msgs[0]->dn, ac->msg->dn) != 0) {
     274          84 :                         ldb_asprintf_errstring(ldb,
     275             :                                                "samldb: %s '%s' already in use!",
     276             :                                                attr, enc_str);
     277          84 :                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
     278             :                 }
     279             :         }
     280      258889 :         talloc_free(res);
     281             : 
     282      258889 :         return LDB_SUCCESS;
     283             : }
     284             : 
     285             : 
     286             : 
     287      107145 : static inline int samldb_sam_account_upn_clash_sub_search(
     288             :         struct samldb_ctx *ac,
     289             :         TALLOC_CTX *mem_ctx,
     290             :         struct ldb_dn *base_dn,
     291             :         const char *attr,
     292             :         const char *value,
     293             :         const char *err_msg
     294             :         )
     295             : {
     296             :         /*
     297             :          * A very specific helper function for samldb_sam_account_upn_clash(),
     298             :          * where we end up doing this same thing several times in a row.
     299             :          */
     300      107145 :         const char * const no_attrs[] = { NULL };
     301      107145 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     302      107145 :         struct ldb_result *res = NULL;
     303        2220 :         int ret;
     304      107145 :         char *enc_value = ldb_binary_encode_string(ac, value);
     305      107145 :         if (enc_value == NULL) {
     306           0 :                 return ldb_module_oom(ac->module);
     307             :         }
     308      107145 :         ret = dsdb_module_search(ac->module, mem_ctx, &res,
     309             :                                  base_dn,
     310             :                                  LDB_SCOPE_SUBTREE, no_attrs,
     311             :                                  DSDB_FLAG_NEXT_MODULE, ac->req,
     312             :                                  "(%s=%s)",
     313             :                                  attr, enc_value);
     314      107145 :         talloc_free(enc_value);
     315             : 
     316      107145 :         if (ret != LDB_SUCCESS) {
     317           0 :                 return ret;
     318      107145 :         } else if (res->count > 1) {
     319           0 :                 return ldb_operr(ldb);
     320      107145 :         } else if (res->count == 1) {
     321         818 :                 if (ldb_dn_compare(res->msgs[0]->dn, ac->msg->dn) != 0){
     322          22 :                         ldb_asprintf_errstring(ldb,
     323             :                                                "samldb: %s '%s' "
     324             :                                                "is already in use %s",
     325             :                                                attr, value, err_msg);
     326             :                         /* different errors for different attrs */
     327          22 :                         if (strcasecmp("userPrincipalName", attr) == 0) {
     328          16 :                                 return LDB_ERR_CONSTRAINT_VIOLATION;
     329             :                         }
     330           6 :                         return LDB_ERR_ENTRY_ALREADY_EXISTS;
     331             :                 }
     332             :         }
     333      104903 :         return LDB_SUCCESS;
     334             : }
     335             : 
     336       39565 : static int samaccountname_bad_chars_check(struct samldb_ctx *ac,
     337             :                                           const char *name)
     338             : {
     339             :         /*
     340             :          * The rules here are based on
     341             :          *
     342             :          * https://social.technet.microsoft.com/wiki/contents/articles/11216.active-directory-requirements-for-creating-objects.aspx
     343             :          *
     344             :          * Windows considers UTF-8 sequences that map to "similar" characters
     345             :          * (e.g. 'a', 'ā') to be the same sAMAccountName, and we don't. Names
     346             :          * that are not valid UTF-8 *are* allowed.
     347             :          *
     348             :          * Additionally, Samba collapses multiple spaces, and Windows doesn't.
     349             :          */
     350       39565 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     351        1076 :         size_t i;
     352             : 
     353      685105 :         for (i = 0; name[i] != '\0'; i++) {
     354      644470 :                 uint8_t c = name[i];
     355      644470 :                 char *p = NULL;
     356      644470 :                 if (c < 32 || c == 127) {
     357           6 :                         ldb_asprintf_errstring(
     358             :                                 ldb,
     359             :                                 "samldb: sAMAccountName contains invalid "
     360             :                                 "0x%.2x character\n", c);
     361           6 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
     362             :                 }
     363      644464 :                 p = strchr("\"[]:;|=+*?<>/\\,", c);
     364      644464 :                 if (p != NULL) {
     365           0 :                         ldb_asprintf_errstring(
     366             :                                 ldb,
     367             :                                 "samldb: sAMAccountName contains invalid "
     368             :                                 "'%c' character\n", c);
     369           0 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
     370             :                 }
     371             :         }
     372             : 
     373       39559 :         if (i == 0) {
     374           0 :                 ldb_asprintf_errstring(
     375             :                         ldb,
     376             :                         "samldb: sAMAccountName is empty\n");
     377           0 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
     378             :         }
     379             : 
     380       39559 :         if (name[i - 1] == '.') {
     381           0 :                 ldb_asprintf_errstring(
     382             :                         ldb,
     383             :                         "samldb: sAMAccountName ends with '.'");
     384           0 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
     385             :         }
     386       38483 :         return LDB_SUCCESS;
     387             : }
     388             : 
     389       39984 : static int samldb_sam_account_upn_clash(struct samldb_ctx *ac)
     390             : {
     391       39984 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     392        1084 :         int ret;
     393       39984 :         struct ldb_dn *base_dn = ldb_get_default_basedn(ldb);
     394       39984 :         TALLOC_CTX *tmp_ctx = NULL;
     395       39984 :         const char *real_sam = NULL;
     396       39984 :         const char *real_upn = NULL;
     397       39984 :         char *implied_sam = NULL;
     398       39984 :         char *implied_upn = NULL;
     399       39984 :         const char *realm = NULL;
     400             : 
     401       39984 :         ret = samldb_get_single_valued_attr(ldb, ac,
     402             :                                             "sAMAccountName",
     403             :                                             &real_sam);
     404       39984 :         if (ret != LDB_SUCCESS) {
     405           0 :                 return ret;
     406             :         }
     407       39984 :         ret = samldb_get_single_valued_attr(ldb, ac,
     408             :                                             "userPrincipalName",
     409             :                                             &real_upn);
     410       39984 :         if (ret != LDB_SUCCESS) {
     411           0 :                 return ret;
     412             :         }
     413       39984 :         if (real_upn == NULL && real_sam == NULL) {
     414             :                 /* Not changing these things, so we're done */
     415           0 :                 return LDB_SUCCESS;
     416             :         }
     417             : 
     418       39984 :         tmp_ctx = talloc_new(ac);
     419       39984 :         realm = samdb_dn_to_dns_domain(tmp_ctx, base_dn);
     420       39984 :         if (realm == NULL) {
     421           0 :                 talloc_free(tmp_ctx);
     422           0 :                 return ldb_operr(ldb);
     423             :         }
     424             : 
     425       39984 :         if (real_upn != NULL) {
     426             :                 /*
     427             :                  * note we take the last @ in the upn because the first (i.e.
     428             :                  * sAMAccountName equivalent) part can contain @.
     429             :                  *
     430             :                  * It is also OK (per Windows) for a UPN to have zero @s.
     431             :                  */
     432       14094 :                 char *at = NULL;
     433       14094 :                 char *upn_realm = NULL;
     434       14094 :                 implied_sam = talloc_strdup(tmp_ctx, real_upn);
     435       14094 :                 if (implied_sam == NULL) {
     436           0 :                         talloc_free(tmp_ctx);
     437           0 :                         return ldb_module_oom(ac->module);
     438             :                 }
     439             : 
     440       14094 :                 at = strrchr(implied_sam, '@');
     441       14094 :                 if (at == NULL) {
     442             :                         /*
     443             :                          * there is no @ in this UPN, so we treat the whole
     444             :                          * thing as a sAMAccountName for the purposes of a
     445             :                          * clash.
     446             :                          */
     447          75 :                         DBG_INFO("samldb: userPrincipalName '%s' contains "
     448             :                                  "no '@' character\n", implied_sam);
     449             :                 } else {
     450             :                         /*
     451             :                          * Now, this upn only implies a sAMAccountName if the
     452             :                          * realm is our realm. So we need to compare the tail
     453             :                          * of the upn to the realm.
     454             :                          */
     455       14019 :                         *at = '\0';
     456       14019 :                         upn_realm = at + 1;
     457       14019 :                         if (strcasecmp(upn_realm, realm) != 0) {
     458             :                                 /* implied_sam is not the implied
     459             :                                  * sAMAccountName after all, because it is
     460             :                                  * from a different realm. */
     461         159 :                                 TALLOC_FREE(implied_sam);
     462             :                         }
     463             :                 }
     464             :         }
     465             : 
     466       39984 :         if (real_sam != NULL) {
     467       39565 :                 implied_upn = talloc_asprintf(tmp_ctx, "%s@%s",
     468             :                                               real_sam, realm);
     469       39565 :                 if (implied_upn == NULL) {
     470           0 :                         talloc_free(tmp_ctx);
     471           0 :                         return ldb_module_oom(ac->module);
     472             :                 }
     473             :         }
     474             : 
     475             :         /*
     476             :          * Now we have all of the actual and implied names, in which to search
     477             :          * for conflicts.
     478             :          */
     479       39984 :         if (real_sam != NULL) {
     480       39565 :                 ret = samldb_sam_account_upn_clash_sub_search(
     481             :                         ac, tmp_ctx, base_dn, "sAMAccountName",
     482             :                         real_sam, "");
     483             : 
     484       39565 :                 if (ret != LDB_SUCCESS) {
     485           0 :                         talloc_free(tmp_ctx);
     486           0 :                         return ret;
     487             :                 }
     488       39565 :                 ret = samaccountname_bad_chars_check(ac, real_sam);
     489       39565 :                 if (ret != LDB_SUCCESS) {
     490           6 :                         talloc_free(tmp_ctx);
     491           6 :                         return ret;
     492             :                 }
     493             :         }
     494       39978 :         if (implied_upn != NULL) {
     495       39559 :                 ret = samldb_sam_account_upn_clash_sub_search(
     496             :                         ac, tmp_ctx, base_dn, "userPrincipalName", implied_upn,
     497             :                         "(implied by sAMAccountName)");
     498             : 
     499       39559 :                 if (ret != LDB_SUCCESS) {
     500           6 :                         talloc_free(tmp_ctx);
     501           6 :                         return ret;
     502             :                 }
     503             :         }
     504       39972 :         if (real_upn != NULL) {
     505       14093 :                 ret = samldb_sam_account_upn_clash_sub_search(
     506             :                         ac, tmp_ctx, base_dn, "userPrincipalName",
     507             :                         real_upn, "");
     508             : 
     509       14093 :                 if (ret != LDB_SUCCESS) {
     510          10 :                         talloc_free(tmp_ctx);
     511          10 :                         return ret;
     512             :                 }
     513             :         }
     514       39962 :         if (implied_sam != NULL) {
     515       13928 :                 ret = samldb_sam_account_upn_clash_sub_search(
     516             :                         ac, tmp_ctx, base_dn, "sAMAccountName", implied_sam,
     517             :                         "(implied by userPrincipalName)");
     518       13928 :                 if (ret != LDB_SUCCESS) {
     519           6 :                         talloc_free(tmp_ctx);
     520           6 :                         return ret;
     521             :                 }
     522             :         }
     523             : 
     524       39956 :         talloc_free(tmp_ctx);
     525       39956 :         return LDB_SUCCESS;
     526             : }
     527             : 
     528             : 
     529             : /* This is run during an add or modify */
     530       39589 : static int samldb_sam_accountname_valid_check(struct samldb_ctx *ac)
     531             : {
     532       39589 :         int ret = 0;
     533        1076 :         bool is_admin;
     534       39589 :         struct security_token *user_token = NULL;
     535       39589 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     536       39589 :         struct ldb_message_element *el = NULL;
     537             : 
     538       40665 :         ret = dsdb_get_expected_new_values(ac,
     539       39589 :                                            ac->msg,
     540             :                                            "samAccountName",
     541             :                                            &el,
     542       39589 :                                            ac->req->operation);
     543       39589 :         if (ret != LDB_SUCCESS) {
     544           0 :                 return ret;
     545             :         }
     546             : 
     547       39589 :         if (el == NULL || el->num_values == 0) {
     548          15 :                 ldb_asprintf_errstring(ldb,
     549             :                         "%08X: samldb: 'samAccountName' can't be deleted/empty!",
     550          15 :                         W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
     551          15 :                 if (ac->req->operation == LDB_ADD) {
     552           3 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
     553             :                 } else {
     554          12 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     555             :                 }
     556             :         }
     557             : 
     558       39574 :         ret = samldb_unique_attr_check(ac, "samAccountName", NULL,
     559             :                                        ldb_get_default_basedn(
     560             :                                                ldb_module_get_ctx(ac->module)));
     561             : 
     562             :         /*
     563             :          * Error code munging to try and match what must be some quite
     564             :          * strange code-paths in Windows
     565             :          */
     566       39574 :         if (ret == LDB_ERR_CONSTRAINT_VIOLATION
     567           2 :             && ac->req->operation == LDB_MODIFY) {
     568           1 :                 ret = LDB_ERR_ATTRIBUTE_OR_VALUE_EXISTS;
     569       39573 :         } else if (ret == LDB_ERR_OBJECT_CLASS_VIOLATION) {
     570           0 :                 ret = LDB_ERR_CONSTRAINT_VIOLATION;
     571             :         }
     572       39574 :         if (ret != LDB_SUCCESS) {
     573          14 :                 return ret;
     574             :         }
     575             : 
     576       39560 :         ret = samldb_sam_account_upn_clash(ac);
     577       39560 :         if (ret != LDB_SUCCESS) {
     578          12 :                 return ret;
     579             :         }
     580             : 
     581       39548 :         if (!ac->need_trailing_dollar) {
     582       34096 :                 return LDB_SUCCESS;
     583             :         }
     584             : 
     585             :         /* This does not permit a single $ */
     586        4472 :         if (el->values[0].length < 2) {
     587           0 :                 ldb_asprintf_errstring(ldb,
     588             :                                        "%08X: samldb: 'samAccountName' "
     589             :                                        "can't just be one character!",
     590           0 :                         W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
     591           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     592             :         }
     593             : 
     594        4472 :         user_token = acl_user_token(ac->module);
     595        4472 :         if (user_token == NULL) {
     596           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
     597             :         }
     598             : 
     599          96 :         is_admin
     600        4472 :                 = security_token_has_builtin_administrators(user_token);
     601             : 
     602        4472 :         if (is_admin) {
     603             :                 /*
     604             :                  * Administrators are allowed to select strange names.
     605             :                  * This is poor practice but not prevented.
     606             :                  */
     607        3545 :                 return false;
     608             :         }
     609             : 
     610         833 :         if (el->values[0].data[el->values[0].length - 1] != '$') {
     611          13 :                 ldb_asprintf_errstring(ldb,
     612             :                                        "%08X: samldb: 'samAccountName' "
     613             :                                        "must have a trailing $!",
     614          13 :                         W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
     615          13 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     616             :         }
     617         820 :         if (el->values[0].data[el->values[0].length - 2] == '$') {
     618           0 :                 ldb_asprintf_errstring(ldb,
     619             :                                        "%08X: samldb: 'samAccountName' "
     620             :                                        "must not have a double trailing $!",
     621           0 :                         W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
     622           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     623             :         }
     624             : 
     625         818 :         return ret;
     626             : }
     627             : 
     628        1023 : static int samldb_schema_attributeid_valid_check(struct samldb_ctx *ac)
     629             : {
     630        1023 :         int ret = samldb_unique_attr_check(ac, "attributeID", "governsID",
     631             :                                            ldb_get_schema_basedn(
     632             :                                                    ldb_module_get_ctx(ac->module)));
     633        1023 :         if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
     634           9 :                 ret = LDB_ERR_UNWILLING_TO_PERFORM;
     635             :         }
     636        1023 :         return ret;
     637             : }
     638             : 
     639         882 : static int samldb_schema_governsid_valid_check(struct samldb_ctx *ac)
     640             : {
     641         882 :         int ret = samldb_unique_attr_check(ac, "governsID", "attributeID",
     642             :                                            ldb_get_schema_basedn(
     643             :                                                    ldb_module_get_ctx(ac->module)));
     644         882 :         if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
     645           9 :                 ret = LDB_ERR_UNWILLING_TO_PERFORM;
     646             :         }
     647         882 :         return ret;
     648             : }
     649             : 
     650      218088 : static int samldb_schema_ldapdisplayname_valid_check(struct samldb_ctx *ac)
     651             : {
     652      218088 :         int ret = samldb_unique_attr_check(ac, "lDAPDisplayName", NULL,
     653             :                                            ldb_get_schema_basedn(
     654             :                                                    ldb_module_get_ctx(ac->module)));
     655      218088 :         if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
     656          36 :                 ret = LDB_ERR_UNWILLING_TO_PERFORM;
     657             :         }
     658      218088 :         return ret;
     659             : }
     660             : 
     661          63 : static int samldb_check_linkid_used(struct samldb_ctx *ac,
     662             :                                     struct dsdb_schema *schema,
     663             :                                     struct ldb_dn *schema_dn,
     664             :                                     struct ldb_context *ldb,
     665             :                                     int32_t linkID,
     666             :                                     bool *found)
     667             : {
     668           0 :         int ret;
     669           0 :         struct ldb_result *ldb_res;
     670             : 
     671          63 :         if (dsdb_attribute_by_linkID(schema, linkID)) {
     672          24 :                 *found = true;
     673          24 :                 return LDB_SUCCESS;
     674             :         }
     675             : 
     676          39 :         ret = dsdb_module_search(ac->module, ac,
     677             :                                  &ldb_res,
     678             :                                  schema_dn, LDB_SCOPE_ONELEVEL, NULL,
     679             :                                  DSDB_FLAG_NEXT_MODULE,
     680             :                                  ac->req,
     681             :                                  "(linkID=%d)", linkID);
     682          39 :         if (ret != LDB_SUCCESS) {
     683           0 :                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
     684             :                               __location__": Searching for linkID=%d failed - %s\n",
     685             :                               linkID,
     686             :                               ldb_errstring(ldb));
     687           0 :                 return ldb_operr(ldb);
     688             :         }
     689             : 
     690          39 :         *found = (ldb_res->count != 0);
     691          39 :         talloc_free(ldb_res);
     692             : 
     693          39 :         return LDB_SUCCESS;
     694             : }
     695             : 
     696             : /* Find the next open forward linkID in the schema. */
     697          27 : static int samldb_generate_next_linkid(struct samldb_ctx *ac,
     698             :                                        struct dsdb_schema *schema,
     699             :                                        int32_t *next_linkID)
     700             : {
     701           0 :         int ret;
     702           0 :         struct ldb_context *ldb;
     703           0 :         struct ldb_dn *schema_dn;
     704          27 :         bool linkID_used = true;
     705             : 
     706             :         /*
     707             :          * Windows starts at about 0xB0000000 in order to stop potential
     708             :          * collisions with future additions to the schema. We pass this
     709             :          * around as a signed int sometimes, but this should be sufficient.
     710             :          */
     711          27 :         *next_linkID = 0x40000000;
     712             : 
     713          27 :         ldb = ldb_module_get_ctx(ac->module);
     714          27 :         schema_dn = ldb_get_schema_basedn(ldb);
     715             : 
     716          69 :         while (linkID_used) {
     717          42 :                 *next_linkID += 2;
     718          42 :                 ret = samldb_check_linkid_used(ac, schema,
     719             :                                                schema_dn, ldb,
     720             :                                                *next_linkID, &linkID_used);
     721          42 :                 if (ret != LDB_SUCCESS) {
     722           0 :                         return ret;
     723             :                 }
     724             :         }
     725             : 
     726          27 :         return LDB_SUCCESS;
     727             : }
     728             : 
     729        1014 : static int samldb_schema_add_handle_linkid(struct samldb_ctx *ac)
     730             : {
     731           0 :         int ret;
     732        1014 :         bool ok, found = false;
     733           0 :         struct ldb_message_element *el;
     734           0 :         const char *enc_str;
     735           0 :         const struct dsdb_attribute *attr;
     736           0 :         struct ldb_context *ldb;
     737           0 :         struct ldb_dn *schema_dn;
     738           0 :         struct dsdb_schema *schema;
     739        1014 :         int32_t new_linkID = 0;
     740             : 
     741        1014 :         ldb = ldb_module_get_ctx(ac->module);
     742        1014 :         schema = dsdb_get_schema(ldb, ac);
     743        1014 :         schema_dn = ldb_get_schema_basedn(ldb);
     744             : 
     745        1014 :         ret = dsdb_get_expected_new_values(ac,
     746        1014 :                                            ac->msg,
     747             :                                            "linkID",
     748             :                                            &el,
     749        1014 :                                            ac->req->operation);
     750        1014 :         if (ret != LDB_SUCCESS) {
     751           0 :                 return ret;
     752             :         }
     753             : 
     754        1014 :         if (el == NULL || el->num_values == 0) {
     755         806 :                 return LDB_SUCCESS;
     756             :         }
     757             : 
     758         208 :         enc_str = ldb_binary_encode(ac, el->values[0]);
     759         208 :         if (enc_str == NULL) {
     760           0 :                 return ldb_module_oom(ac->module);
     761             :         }
     762             : 
     763         208 :         ok = (strcmp(enc_str, "0") == 0);
     764         208 :         if (ok) {
     765           0 :                 return LDB_SUCCESS;
     766             :         }
     767             : 
     768             :         /*
     769             :          * This OID indicates that the caller wants the linkID
     770             :          * to be automatically generated. We therefore assign
     771             :          * it the next open linkID.
     772             :          */
     773         208 :         ok = (strcmp(enc_str, "1.2.840.113556.1.2.50") == 0);
     774         208 :         if (ok) {
     775          27 :                 ret = samldb_generate_next_linkid(ac, schema, &new_linkID);
     776          27 :                 if (ret != LDB_SUCCESS) {
     777           0 :                         return ret;
     778             :                 }
     779             : 
     780          27 :                 ldb_msg_remove_element(ac->msg, el);
     781          27 :                 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, "linkID",
     782             :                                         new_linkID);
     783          27 :                 return ret;
     784             :         }
     785             : 
     786             :         /*
     787             :          * Using either the attributeID or lDAPDisplayName of
     788             :          * another attribute in the linkID field indicates that
     789             :          * we should make this the backlink of that attribute.
     790             :          */
     791         181 :         attr = dsdb_attribute_by_attributeID_oid(schema, enc_str);
     792         181 :         if (attr == NULL) {
     793         163 :                 attr = dsdb_attribute_by_lDAPDisplayName(schema, enc_str);
     794             :         }
     795             : 
     796         181 :         if (attr != NULL) {
     797             :                 /*
     798             :                  * The attribute we're adding this as a backlink of must
     799             :                  * be a forward link.
     800             :                  */
     801          39 :                 if (attr->linkID % 2 != 0) {
     802          18 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     803             :                 }
     804             : 
     805          21 :                 new_linkID = attr->linkID + 1;
     806             : 
     807             :                 /* Make sure that this backlink doesn't already exist. */
     808          21 :                 ret = samldb_check_linkid_used(ac, schema,
     809             :                                                schema_dn, ldb,
     810             :                                                new_linkID, &found);
     811          21 :                 if (ret != LDB_SUCCESS) {
     812           0 :                         return ret;
     813             :                 }
     814             : 
     815          21 :                 if (found) {
     816           9 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
     817             :                 }
     818             : 
     819          12 :                 ldb_msg_remove_element(ac->msg, el);
     820          12 :                 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg, "linkID",
     821             :                                         new_linkID);
     822          12 :                 return ret;
     823             :         }
     824             : 
     825         142 :         schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ac->module));
     826         142 :         ret = samldb_unique_attr_check(ac, "linkID", NULL, schema_dn);
     827         142 :         if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
     828           9 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     829             :         } else {
     830         133 :                 return ret;
     831             :         }
     832             : }
     833             : 
     834           9 : static int samldb_check_mapiid_used(struct samldb_ctx *ac,
     835             :                                     struct dsdb_schema *schema,
     836             :                                     struct ldb_dn *schema_dn,
     837             :                                     struct ldb_context *ldb,
     838             :                                     int32_t mapiid,
     839             :                                     bool *found)
     840             : {
     841           0 :         int ret;
     842           0 :         struct ldb_result *ldb_res;
     843             : 
     844           9 :         ret = dsdb_module_search(ac->module, ac,
     845             :                                  &ldb_res,
     846             :                                  schema_dn, LDB_SCOPE_ONELEVEL, NULL,
     847             :                                  DSDB_FLAG_NEXT_MODULE,
     848             :                                  ac->req,
     849             :                                  "(mAPIID=%d)", mapiid);
     850           9 :         if (ret != LDB_SUCCESS) {
     851           0 :                 ldb_debug_set(ldb, LDB_DEBUG_ERROR,
     852             :                               __location__": Searching for mAPIID=%d failed - %s\n",
     853             :                               mapiid,
     854             :                               ldb_errstring(ldb));
     855           0 :                 return ldb_operr(ldb);
     856             :         }
     857             : 
     858           9 :         *found = (ldb_res->count != 0);
     859           9 :         talloc_free(ldb_res);
     860             : 
     861           9 :         return LDB_SUCCESS;
     862             : }
     863             : 
     864           9 : static int samldb_generate_next_mapiid(struct samldb_ctx *ac,
     865             :                                        struct dsdb_schema *schema,
     866             :                                        int32_t *next_mapiid)
     867             : {
     868           0 :         int ret;
     869           0 :         struct ldb_context *ldb;
     870           0 :         struct ldb_dn *schema_dn;
     871           9 :         bool mapiid_used = true;
     872             : 
     873             :         /* Windows' generation seems to start about here */
     874           9 :         *next_mapiid = 60000;
     875             : 
     876           9 :         ldb = ldb_module_get_ctx(ac->module);
     877           9 :         schema_dn = ldb_get_schema_basedn(ldb);
     878             : 
     879          18 :         while (mapiid_used) {
     880           9 :                 *next_mapiid += 1;
     881           9 :                 ret = samldb_check_mapiid_used(ac, schema,
     882             :                                                schema_dn, ldb,
     883             :                                                *next_mapiid, &mapiid_used);
     884           9 :                 if (ret != LDB_SUCCESS) {
     885           0 :                         return ret;
     886             :                 }
     887             :         }
     888             : 
     889           9 :         return LDB_SUCCESS;
     890             : }
     891             : 
     892         978 : static int samldb_schema_add_handle_mapiid(struct samldb_ctx *ac)
     893             : {
     894           0 :         int ret;
     895           0 :         bool ok;
     896           0 :         struct ldb_message_element *el;
     897           0 :         const char *enc_str;
     898           0 :         struct ldb_context *ldb;
     899           0 :         struct ldb_dn *schema_dn;
     900           0 :         struct dsdb_schema *schema;
     901         978 :         int32_t new_mapiid = 0;
     902             : 
     903             :         /*
     904             :          * The mAPIID of a new attribute should be automatically generated
     905             :          * if a specific OID is put as the mAPIID, as according to
     906             :          * [MS-ADTS] 3.1.1.2.3.2.
     907             :          */
     908             : 
     909         978 :         ldb = ldb_module_get_ctx(ac->module);
     910         978 :         schema = dsdb_get_schema(ldb, ac);
     911         978 :         schema_dn = ldb_get_schema_basedn(ldb);
     912             : 
     913         978 :         ret = dsdb_get_expected_new_values(ac,
     914         978 :                                            ac->msg,
     915             :                                            "mAPIID",
     916             :                                            &el,
     917         978 :                                            ac->req->operation);
     918         978 :         if (ret != LDB_SUCCESS) {
     919           0 :                 return ret;
     920             :         }
     921             : 
     922         978 :         if (el == NULL || el->num_values == 0) {
     923         960 :                 return LDB_SUCCESS;
     924             :         }
     925             : 
     926          18 :         enc_str = ldb_binary_encode(ac, el->values[0]);
     927          18 :         if (enc_str == NULL) {
     928           0 :                 return ldb_module_oom(ac->module);
     929             :         }
     930             : 
     931          18 :         ok = (strcmp(enc_str, "1.2.840.113556.1.2.49") == 0);
     932          18 :         if (ok) {
     933           9 :                 ret = samldb_generate_next_mapiid(ac, schema,
     934             :                                                   &new_mapiid);
     935           9 :                 if (ret != LDB_SUCCESS) {
     936           0 :                         return ret;
     937             :                 }
     938             : 
     939           9 :                 ldb_msg_remove_element(ac->msg, el);
     940           9 :                 ret = samdb_msg_add_int(ldb, ac->msg, ac->msg,
     941             :                                         "mAPIID", new_mapiid);
     942           9 :                 return ret;
     943             :         }
     944             : 
     945           9 :         schema_dn = ldb_get_schema_basedn(ldb_module_get_ctx(ac->module));
     946           9 :         ret = samldb_unique_attr_check(ac, "mAPIID", NULL, schema_dn);
     947           9 :         if (ret == LDB_ERR_ENTRY_ALREADY_EXISTS) {
     948           9 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
     949             :         } else {
     950           0 :                 return ret;
     951             :         }
     952             : }
     953             : 
     954             : /* sAMAccountName handling */
     955        6541 : static int samldb_generate_sAMAccountName(struct samldb_ctx *ac,
     956             :                                           struct ldb_message *msg)
     957             : {
     958        6541 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
     959           3 :         char *name;
     960             : 
     961             :         /*
     962             :          * This is currently a Samba-only behaviour, to add a trailing
     963             :          * $ even for the generated accounts.
     964             :          */
     965             : 
     966        6541 :         if (ac->need_trailing_dollar) {
     967             :                 /* Format: $000000-00000000000$ */
     968         350 :                 name = talloc_asprintf(msg, "$%.6X-%.6X%.5X$",
     969         350 :                                        (unsigned int)generate_random(),
     970         350 :                                        (unsigned int)generate_random(),
     971         350 :                                        (unsigned int)generate_random());
     972             :         } else {
     973             :                 /* Format: $000000-000000000000 */
     974             : 
     975        6191 :                 name = talloc_asprintf(msg, "$%.6X-%.6X%.6X",
     976        6191 :                                        (unsigned int)generate_random(),
     977        6191 :                                        (unsigned int)generate_random(),
     978        6191 :                                        (unsigned int)generate_random());
     979             :         }
     980        6541 :         if (name == NULL) {
     981           0 :                 return ldb_oom(ldb);
     982             :         }
     983        6541 :         return ldb_msg_add_steal_string(msg, "sAMAccountName", name);
     984             : }
     985             : 
     986       38677 : static int samldb_check_sAMAccountName(struct samldb_ctx *ac)
     987             : {
     988        1066 :         int ret;
     989             : 
     990       38677 :         if (ldb_msg_find_element(ac->msg, "sAMAccountName") == NULL) {
     991        6541 :                 ret = samldb_generate_sAMAccountName(ac, ac->msg);
     992        6541 :                 if (ret != LDB_SUCCESS) {
     993           0 :                         return ret;
     994             :                 }
     995             :         }
     996             : 
     997       38677 :         ret = samldb_sam_accountname_valid_check(ac);
     998       38677 :         if (ret != LDB_SUCCESS) {
     999           8 :                 return ret;
    1000             :         }
    1001             : 
    1002       38669 :         return samldb_next_step(ac);
    1003             : }
    1004             : 
    1005             : 
    1006       33581 : static bool samldb_msg_add_sid(struct ldb_message *msg,
    1007             :                                 const char *name,
    1008             :                                 const struct dom_sid *sid)
    1009             : {
    1010         172 :         struct ldb_val v;
    1011         172 :         enum ndr_err_code ndr_err;
    1012             : 
    1013       33581 :         ndr_err = ndr_push_struct_blob(&v, msg, sid,
    1014             :                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
    1015       33581 :         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    1016           0 :                 return false;
    1017             :         }
    1018       33581 :         return (ldb_msg_add_value(msg, name, &v, NULL) == 0);
    1019             : }
    1020             : 
    1021             : 
    1022             : /* allocate a SID using our RID Set */
    1023       33536 : static int samldb_allocate_sid(struct samldb_ctx *ac)
    1024             : {
    1025         172 :         uint32_t rid;
    1026         172 :         struct dom_sid *sid;
    1027       33536 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    1028         172 :         int ret;
    1029             : 
    1030       33536 :         ret = ridalloc_allocate_rid(ac->module, &rid, ac->req);
    1031       33536 :         if (ret != LDB_SUCCESS) {
    1032           0 :                 return ret;
    1033             :         }
    1034             : 
    1035       33536 :         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
    1036       33536 :         if (sid == NULL) {
    1037           0 :                 return ldb_module_oom(ac->module);
    1038             :         }
    1039             : 
    1040       33536 :         if ( ! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
    1041           0 :                 return ldb_operr(ldb);
    1042             :         }
    1043             : 
    1044       33536 :         return samldb_next_step(ac);
    1045             : }
    1046             : 
    1047             : /*
    1048             :   see if a krbtgt_number is available
    1049             :  */
    1050          92 : static bool samldb_krbtgtnumber_available(struct samldb_ctx *ac,
    1051             :                                           uint32_t krbtgt_number)
    1052             : {
    1053          92 :         TALLOC_CTX *tmp_ctx = talloc_new(ac);
    1054           0 :         struct ldb_result *res;
    1055          92 :         const char * const no_attrs[] = { NULL };
    1056           0 :         int ret;
    1057             : 
    1058          92 :         ret = dsdb_module_search(ac->module, tmp_ctx, &res,
    1059             :                                  ldb_get_default_basedn(ldb_module_get_ctx(ac->module)),
    1060             :                                  LDB_SCOPE_SUBTREE, no_attrs,
    1061             :                                  DSDB_FLAG_NEXT_MODULE,
    1062             :                                  ac->req,
    1063             :                                  "(msDS-SecondaryKrbTgtNumber=%u)",
    1064             :                                  krbtgt_number);
    1065          92 :         if (ret == LDB_SUCCESS && res->count == 0) {
    1066          92 :                 talloc_free(tmp_ctx);
    1067          92 :                 return true;
    1068             :         }
    1069           0 :         talloc_free(tmp_ctx);
    1070           0 :         return false;
    1071             : }
    1072             : 
    1073             : /* special handling for add in RODC join */
    1074          92 : static int samldb_rodc_add(struct samldb_ctx *ac)
    1075             : {
    1076          92 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    1077           0 :         uint32_t krbtgt_number, i_start, i;
    1078           0 :         int ret;
    1079           0 :         struct ldb_val newpass_utf16;
    1080             : 
    1081             :         /* find a unused msDS-SecondaryKrbTgtNumber */
    1082          92 :         i_start = generate_random() & 0xFFFF;
    1083          92 :         if (i_start == 0) {
    1084           0 :                 i_start = 1;
    1085             :         }
    1086             : 
    1087          92 :         for (i=i_start; i<=0xFFFF; i++) {
    1088          92 :                 if (samldb_krbtgtnumber_available(ac, i)) {
    1089          92 :                         krbtgt_number = i;
    1090          92 :                         goto found;
    1091             :                 }
    1092             :         }
    1093           0 :         for (i=1; i<i_start; i++) {
    1094           0 :                 if (samldb_krbtgtnumber_available(ac, i)) {
    1095           0 :                         krbtgt_number = i;
    1096           0 :                         goto found;
    1097             :                 }
    1098             :         }
    1099             : 
    1100           0 :         ldb_asprintf_errstring(ldb,
    1101             :                                "%08X: Unable to find available msDS-SecondaryKrbTgtNumber",
    1102           0 :                                W_ERROR_V(WERR_NO_SYSTEM_RESOURCES));
    1103           0 :         return LDB_ERR_OTHER;
    1104             : 
    1105          92 : found:
    1106             : 
    1107          92 :         ldb_msg_remove_attr(ac->msg, "msDS-SecondaryKrbTgtNumber");
    1108          92 :         ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg,
    1109             :                                     "msDS-SecondaryKrbTgtNumber", krbtgt_number,
    1110             :                                     LDB_FLAG_INTERNAL_DISABLE_VALIDATION);
    1111          92 :         if (ret != LDB_SUCCESS) {
    1112           0 :                 return ldb_operr(ldb);
    1113             :         }
    1114             : 
    1115          92 :         ret = ldb_msg_add_fmt(ac->msg, "sAMAccountName", "krbtgt_%u",
    1116             :                               krbtgt_number);
    1117          92 :         if (ret != LDB_SUCCESS) {
    1118           0 :                 return ldb_operr(ldb);
    1119             :         }
    1120             : 
    1121          92 :         newpass_utf16 = data_blob_talloc_zero(ac->module, 256);
    1122          92 :         if (newpass_utf16.data == NULL) {
    1123           0 :                 return ldb_oom(ldb);
    1124             :         }
    1125             :         /*
    1126             :          * Note that the password_hash module will ignore
    1127             :          * this value and use it's own generate_secret_buffer()
    1128             :          * that's why we can just use generate_random_buffer()
    1129             :          * here.
    1130             :          */
    1131          92 :         generate_random_buffer(newpass_utf16.data, newpass_utf16.length);
    1132          92 :         ret = ldb_msg_add_steal_value(ac->msg, "clearTextPassword", &newpass_utf16);
    1133          92 :         if (ret != LDB_SUCCESS) {
    1134           0 :                 return ldb_operr(ldb);
    1135             :         }
    1136             : 
    1137          92 :         return samldb_next_step(ac);
    1138             : }
    1139             : 
    1140       33672 : static int samldb_find_for_defaultObjectCategory(struct samldb_ctx *ac)
    1141             : {
    1142       33672 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    1143        5918 :         struct ldb_result *res;
    1144       33672 :         const char * const no_attrs[] = { NULL };
    1145        5918 :         int ret;
    1146             : 
    1147       33672 :         ac->res_dn = NULL;
    1148             : 
    1149       33672 :         ret = dsdb_module_search(ac->module, ac, &res,
    1150             :                                  ac->dn, LDB_SCOPE_BASE, no_attrs,
    1151             :                                  DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT
    1152             :                                  | DSDB_FLAG_NEXT_MODULE,
    1153             :                                  ac->req,
    1154             :                                  "(objectClass=classSchema)");
    1155       33672 :         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    1156             :                 /* Don't be pricky when the DN doesn't exist if we have the */
    1157             :                 /* RELAX control specified */
    1158         264 :                 if (ldb_request_get_control(ac->req,
    1159             :                                             LDB_CONTROL_RELAX_OID) == NULL) {
    1160           0 :                         ldb_set_errstring(ldb,
    1161             :                                           "samldb_find_defaultObjectCategory: "
    1162             :                                           "Invalid DN for 'defaultObjectCategory'!");
    1163           0 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
    1164             :                 }
    1165             :         }
    1166       33672 :         if ((ret != LDB_ERR_NO_SUCH_OBJECT) && (ret != LDB_SUCCESS)) {
    1167           0 :                 return ret;
    1168             :         }
    1169             : 
    1170       33672 :         if (ret == LDB_SUCCESS) {
    1171             :                 /* ensure the defaultObjectCategory has a full GUID */
    1172        5874 :                 struct ldb_message *m;
    1173       33408 :                 m = ldb_msg_new(ac->msg);
    1174       33408 :                 if (m == NULL) {
    1175           0 :                         return ldb_oom(ldb);
    1176             :                 }
    1177       33408 :                 m->dn = ac->msg->dn;
    1178       33408 :                 if (ldb_msg_add_string(m, "defaultObjectCategory",
    1179       33408 :                                        ldb_dn_get_extended_linearized(m, res->msgs[0]->dn, 1)) !=
    1180             :                     LDB_SUCCESS) {
    1181           0 :                         return ldb_oom(ldb);
    1182             :                 }
    1183       33408 :                 m->elements[0].flags = LDB_FLAG_MOD_REPLACE;
    1184             : 
    1185       33408 :                 ret = dsdb_module_modify(ac->module, m,
    1186             :                                          DSDB_FLAG_NEXT_MODULE,
    1187             :                                          ac->req);
    1188       33408 :                 if (ret != LDB_SUCCESS) {
    1189           0 :                         return ret;
    1190             :                 }
    1191             :         }
    1192             : 
    1193             : 
    1194       33672 :         ac->res_dn = ac->dn;
    1195             : 
    1196       33672 :         return samldb_next_step(ac);
    1197             : }
    1198             : 
    1199             : /**
    1200             :  * msDS-IntId attributeSchema attribute handling
    1201             :  * during LDB_ADD request processing
    1202             :  */
    1203      184328 : static int samldb_add_handle_msDS_IntId(struct samldb_ctx *ac)
    1204             : {
    1205       32978 :         int ret;
    1206       32978 :         bool id_exists;
    1207       32978 :         uint32_t msds_intid;
    1208       32978 :         int32_t system_flags;
    1209       32978 :         struct ldb_context *ldb;
    1210       32978 :         struct ldb_result *ldb_res;
    1211       32978 :         struct ldb_dn *schema_dn;
    1212       32978 :         struct samldb_msds_intid_persistant *msds_intid_struct;
    1213       32978 :         struct dsdb_schema *schema;
    1214             : 
    1215      184328 :         ldb = ldb_module_get_ctx(ac->module);
    1216      184328 :         schema_dn = ldb_get_schema_basedn(ldb);
    1217             : 
    1218             :         /* replicated update should always go through */
    1219      184328 :         if (ldb_request_get_control(ac->req,
    1220             :                                     DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
    1221           0 :                 return LDB_SUCCESS;
    1222             :         }
    1223             : 
    1224             :         /* msDS-IntId is handled by system and should never be
    1225             :          * passed by clients */
    1226      184328 :         if (ldb_msg_find_element(ac->msg, "msDS-IntId")) {
    1227          18 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1228             :         }
    1229             : 
    1230             :         /* do not generate msDS-IntId if Relax control is passed */
    1231      184310 :         if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
    1232      151087 :                 return LDB_SUCCESS;
    1233             :         }
    1234             : 
    1235             :         /* check Functional Level */
    1236         245 :         if (dsdb_functional_level(ldb) < DS_DOMAIN_FUNCTION_2003) {
    1237          53 :                 return LDB_SUCCESS;
    1238             :         }
    1239             : 
    1240             :         /* check systemFlags for SCHEMA_BASE_OBJECT flag */
    1241         192 :         system_flags = ldb_msg_find_attr_as_int(ac->msg, "systemFlags", 0);
    1242         192 :         if (system_flags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) {
    1243           0 :                 return LDB_SUCCESS;
    1244             :         }
    1245         192 :         schema = dsdb_get_schema(ldb, NULL);
    1246         192 :         if (!schema) {
    1247           0 :                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
    1248             :                               "samldb_schema_info_update: no dsdb_schema loaded");
    1249           0 :                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
    1250           0 :                 return ldb_operr(ldb);
    1251             :         }
    1252             : 
    1253         192 :         msds_intid_struct = (struct samldb_msds_intid_persistant*) ldb_get_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE);
    1254         192 :         if (!msds_intid_struct) {
    1255         136 :                 msds_intid_struct = talloc(ldb, struct samldb_msds_intid_persistant);
    1256             :                 /* Generate new value for msDs-IntId
    1257             :                 * Value should be in 0x80000000..0xBFFFFFFF range */
    1258         136 :                 msds_intid = generate_random() % 0X3FFFFFFF;
    1259         136 :                 msds_intid += 0x80000000;
    1260         136 :                 msds_intid_struct->msds_intid = msds_intid;
    1261         136 :                 DEBUG(2, ("No samldb_msds_intid_persistant struct, allocating a new one\n"));
    1262             :         } else {
    1263          56 :                 msds_intid = msds_intid_struct->msds_intid;
    1264             :         }
    1265             : 
    1266             :         /* probe id values until unique one is found */
    1267           0 :         do {
    1268         192 :                 msds_intid++;
    1269         192 :                 if (msds_intid > 0xBFFFFFFF) {
    1270           0 :                         msds_intid = 0x80000001;
    1271             :                 }
    1272             :                 /*
    1273             :                  * We search in the schema if we have already this
    1274             :                  * intid (using dsdb_attribute_by_attributeID_id
    1275             :                  * because in the range 0x80000000 0xBFFFFFFF,
    1276             :                  * attributeID is a DSDB_ATTID_TYPE_INTID).
    1277             :                  *
    1278             :                  * If so generate another random value.
    1279             :                  *
    1280             :                  * We have to check the DB in case someone else has
    1281             :                  * modified the database while we are doing our
    1282             :                  * changes too (this case should be very very rare) in
    1283             :                  * order to be sure.
    1284             :                  */
    1285         192 :                 if (dsdb_attribute_by_attributeID_id(schema, msds_intid)) {
    1286           0 :                         id_exists = true;
    1287           0 :                         msds_intid = generate_random() % 0X3FFFFFFF;
    1288           0 :                         msds_intid += 0x80000000;
    1289           0 :                         continue;
    1290             :                 }
    1291             : 
    1292             : 
    1293         192 :                 ret = dsdb_module_search(ac->module, ac,
    1294             :                                          &ldb_res,
    1295             :                                          schema_dn, LDB_SCOPE_ONELEVEL, NULL,
    1296             :                                          DSDB_FLAG_NEXT_MODULE,
    1297             :                                          ac->req,
    1298             :                                          "(msDS-IntId=%d)", msds_intid);
    1299         192 :                 if (ret != LDB_SUCCESS) {
    1300           0 :                         ldb_debug_set(ldb, LDB_DEBUG_ERROR,
    1301             :                                       __location__": Searching for msDS-IntId=%d failed - %s\n",
    1302             :                                       msds_intid,
    1303             :                                       ldb_errstring(ldb));
    1304           0 :                         return ldb_operr(ldb);
    1305             :                 }
    1306         192 :                 id_exists = (ldb_res->count > 0);
    1307         192 :                 talloc_free(ldb_res);
    1308             : 
    1309         192 :         } while(id_exists);
    1310         192 :         msds_intid_struct->msds_intid = msds_intid;
    1311         192 :         ldb_set_opaque(ldb, SAMLDB_MSDS_INTID_OPAQUE, msds_intid_struct);
    1312             : 
    1313         192 :         return samdb_msg_add_int(ldb, ac->msg, ac->msg, "msDS-IntId",
    1314             :                                  msds_intid);
    1315             : }
    1316             : 
    1317             : 
    1318             : /*
    1319             :  * samldb_add_entry (async)
    1320             :  */
    1321             : 
    1322      260550 : static int samldb_add_entry_callback(struct ldb_request *req,
    1323             :                                         struct ldb_reply *ares)
    1324             : {
    1325       40622 :         struct ldb_context *ldb;
    1326       40622 :         struct samldb_ctx *ac;
    1327       40622 :         int ret;
    1328             : 
    1329      260550 :         ac = talloc_get_type(req->context, struct samldb_ctx);
    1330      260550 :         ldb = ldb_module_get_ctx(ac->module);
    1331             : 
    1332      260550 :         if (!ares) {
    1333           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    1334             :                                         LDB_ERR_OPERATIONS_ERROR);
    1335             :         }
    1336             : 
    1337      260550 :         if (ares->type == LDB_REPLY_REFERRAL) {
    1338           0 :                 return ldb_module_send_referral(ac->req, ares->referral);
    1339             :         }
    1340             : 
    1341      260550 :         if (ares->error != LDB_SUCCESS) {
    1342         204 :                 return ldb_module_done(ac->req, ares->controls,
    1343             :                                         ares->response, ares->error);
    1344             :         }
    1345      260346 :         if (ares->type != LDB_REPLY_DONE) {
    1346           0 :                 ldb_asprintf_errstring(ldb, "Invalid LDB reply type %d", ares->type);
    1347           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    1348             :                                         LDB_ERR_OPERATIONS_ERROR);
    1349             :         }
    1350             : 
    1351             :         /* The caller may wish to get controls back from the add */
    1352      260346 :         ac->ares = talloc_steal(ac, ares);
    1353             : 
    1354      260346 :         ret = samldb_next_step(ac);
    1355      260346 :         if (ret != LDB_SUCCESS) {
    1356           0 :                 return ldb_module_done(ac->req, NULL, NULL, ret);
    1357             :         }
    1358      219725 :         return ret;
    1359             : }
    1360             : 
    1361      260538 : static int samldb_add_entry(struct samldb_ctx *ac)
    1362             : {
    1363       40622 :         struct ldb_context *ldb;
    1364       40622 :         struct ldb_request *req;
    1365       40622 :         int ret;
    1366             : 
    1367      260538 :         ldb = ldb_module_get_ctx(ac->module);
    1368             : 
    1369      301160 :         ret = ldb_build_add_req(&req, ldb, ac,
    1370      260538 :                                 ac->msg,
    1371      219916 :                                 ac->req->controls,
    1372             :                                 ac, samldb_add_entry_callback,
    1373             :                                 ac->req);
    1374      260538 :         LDB_REQ_SET_LOCATION(req);
    1375      260538 :         if (ret != LDB_SUCCESS) {
    1376           0 :                 return ret;
    1377             :         }
    1378             : 
    1379      260538 :         return ldb_next_request(ac->module, req);
    1380             : }
    1381             : 
    1382             : /*
    1383             :  * return true if msg carries an attributeSchema that is intended to be RODC
    1384             :  * filtered but is also a system-critical attribute.
    1385             :  */
    1386      218032 : static bool check_rodc_critical_attribute(struct ldb_message *msg)
    1387             : {
    1388       38896 :         uint32_t schemaFlagsEx, searchFlags, rodc_filtered_flags;
    1389             : 
    1390      218032 :         schemaFlagsEx = ldb_msg_find_attr_as_uint(msg, "schemaFlagsEx", 0);
    1391      218032 :         searchFlags = ldb_msg_find_attr_as_uint(msg, "searchFlags", 0);
    1392      218032 :         rodc_filtered_flags = (SEARCH_FLAG_RODC_ATTRIBUTE
    1393             :                               | SEARCH_FLAG_CONFIDENTIAL);
    1394             : 
    1395      218032 :         if ((schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) &&
    1396       49350 :                 ((searchFlags & rodc_filtered_flags) == rodc_filtered_flags)) {
    1397           0 :                 return true;
    1398             :         } else {
    1399      218032 :                 return false;
    1400             :         }
    1401             : }
    1402             : 
    1403             : 
    1404      256709 : static int samldb_fill_object(struct samldb_ctx *ac)
    1405             : {
    1406      256709 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    1407       39962 :         int ret;
    1408             : 
    1409             :         /* Add information for the different account types */
    1410      256709 :         switch(ac->type) {
    1411       29973 :         case SAMLDB_TYPE_USER: {
    1412       29973 :                 struct ldb_control *rodc_control = ldb_request_get_control(ac->req,
    1413             :                                                                            LDB_CONTROL_RODC_DCPROMO_OID);
    1414       29973 :                 if (rodc_control != NULL) {
    1415             :                         /* see [MS-ADTS] 3.1.1.3.4.1.23 LDAP_SERVER_RODC_DCPROMO_OID */
    1416          92 :                         rodc_control->critical = false;
    1417          92 :                         ret = samldb_add_step(ac, samldb_rodc_add);
    1418          92 :                         if (ret != LDB_SUCCESS) return ret;
    1419             :                 }
    1420             : 
    1421             :                 /* check if we have a valid sAMAccountName */
    1422       29973 :                 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
    1423       29973 :                 if (ret != LDB_SUCCESS) return ret;
    1424             : 
    1425       29973 :                 ret = samldb_add_step(ac, samldb_add_entry);
    1426       29973 :                 if (ret != LDB_SUCCESS) return ret;
    1427       29752 :                 break;
    1428             :         }
    1429             : 
    1430        8704 :         case SAMLDB_TYPE_GROUP: {
    1431             :                 /* check if we have a valid sAMAccountName */
    1432        8704 :                 ret = samldb_add_step(ac, samldb_check_sAMAccountName);
    1433        8704 :                 if (ret != LDB_SUCCESS) return ret;
    1434             : 
    1435        8704 :                 ret = samldb_add_step(ac, samldb_add_entry);
    1436        8704 :                 if (ret != LDB_SUCCESS) return ret;
    1437        7859 :                 break;
    1438             :         }
    1439             : 
    1440       33704 :         case SAMLDB_TYPE_CLASS: {
    1441       33704 :                 const char *lDAPDisplayName = NULL;
    1442        5918 :                 const struct ldb_val *rdn_value, *def_obj_cat_val;
    1443       33704 :                 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "objectClassCategory", -2);
    1444             : 
    1445             :                 /* As discussed with Microsoft through dochelp in April 2012 this is the behavior of windows*/
    1446       33704 :                 if (!ldb_msg_find_element(ac->msg, "subClassOf")) {
    1447         162 :                         ret = ldb_msg_add_string(ac->msg, "subClassOf", "top");
    1448         162 :                         if (ret != LDB_SUCCESS) return ret;
    1449             :                 }
    1450             : 
    1451       33704 :                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
    1452             :                                                   "rdnAttId", "cn");
    1453       33704 :                 if (ret != LDB_SUCCESS) return ret;
    1454             : 
    1455             :                 /* do not allow one to mark an attributeSchema as RODC filtered if it
    1456             :                  * is system-critical */
    1457       33704 :                 if (check_rodc_critical_attribute(ac->msg)) {
    1458           0 :                         ldb_asprintf_errstring(ldb, "Refusing schema add of %s - cannot combine critical class with RODC filtering",
    1459           0 :                                                ldb_dn_get_linearized(ac->msg->dn));
    1460           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    1461             :                 }
    1462             : 
    1463       33704 :                 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
    1464       33704 :                 if (rdn_value == NULL) {
    1465           0 :                         return ldb_operr(ldb);
    1466             :                 }
    1467       33704 :                 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
    1468             :                         /* the RDN has prefix "CN" */
    1469         628 :                         ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
    1470         628 :                                 samdb_cn_to_lDAPDisplayName(ac->msg,
    1471         628 :                                                             (const char *) rdn_value->data));
    1472         628 :                         if (ret != LDB_SUCCESS) {
    1473           0 :                                 ldb_oom(ldb);
    1474           0 :                                 return ret;
    1475             :                         }
    1476             :                 }
    1477             : 
    1478       33704 :                 lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
    1479             :                                                               "lDAPDisplayName",
    1480             :                                                               NULL);
    1481       33704 :                 ret = ldb_valid_attr_name(lDAPDisplayName);
    1482       33704 :                 if (ret != 1 ||
    1483       33704 :                     lDAPDisplayName[0] == '*' ||
    1484       27786 :                     lDAPDisplayName[0] == '@')
    1485             :                 {
    1486           0 :                         return dsdb_module_werror(ac->module,
    1487             :                                                   LDB_ERR_UNWILLING_TO_PERFORM,
    1488             :                                                   WERR_DS_INVALID_LDAP_DISPLAY_NAME,
    1489             :                                                   "lDAPDisplayName is invalid");
    1490             :                 }
    1491             : 
    1492       33704 :                 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
    1493           0 :                         struct GUID guid;
    1494             :                         /* a new GUID */
    1495         702 :                         guid = GUID_random();
    1496         702 :                         ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
    1497         702 :                         if (ret != LDB_SUCCESS) {
    1498           0 :                                 ldb_oom(ldb);
    1499           0 :                                 return ret;
    1500             :                         }
    1501             :                 }
    1502             : 
    1503       33704 :                 def_obj_cat_val = ldb_msg_find_ldb_val(ac->msg,
    1504             :                                                        "defaultObjectCategory");
    1505       33704 :                 if (def_obj_cat_val != NULL) {
    1506             :                         /* "defaultObjectCategory" has been set by the caller.
    1507             :                          * Do some checks for consistency.
    1508             :                          * NOTE: The real constraint check (that
    1509             :                          * 'defaultObjectCategory' is the DN of the new
    1510             :                          * objectclass or any parent of it) is still incomplete.
    1511             :                          * For now we say that 'defaultObjectCategory' is valid
    1512             :                          * if it exists and it is of objectclass "classSchema".
    1513             :                          */
    1514       33120 :                         ac->dn = ldb_dn_from_ldb_val(ac, ldb, def_obj_cat_val);
    1515       33120 :                         if (ac->dn == NULL) {
    1516           0 :                                 ldb_set_errstring(ldb,
    1517             :                                                   "Invalid DN for 'defaultObjectCategory'!");
    1518           0 :                                 return LDB_ERR_CONSTRAINT_VIOLATION;
    1519             :                         }
    1520             :                 } else {
    1521             :                         /* "defaultObjectCategory" has not been set by the
    1522             :                          * caller. Use the entry DN for it. */
    1523         584 :                         ac->dn = ac->msg->dn;
    1524             : 
    1525         584 :                         ret = ldb_msg_add_string(ac->msg, "defaultObjectCategory",
    1526         584 :                                                  ldb_dn_alloc_linearized(ac->msg, ac->dn));
    1527         584 :                         if (ret != LDB_SUCCESS) {
    1528           0 :                                 ldb_oom(ldb);
    1529           0 :                                 return ret;
    1530             :                         }
    1531             :                 }
    1532             : 
    1533       33704 :                 ret = samldb_add_step(ac, samldb_add_entry);
    1534       33704 :                 if (ret != LDB_SUCCESS) return ret;
    1535             : 
    1536             :                 /* Now perform the checks for the 'defaultObjectCategory'. The
    1537             :                  * lookup DN was already saved in "ac->dn" */
    1538       33704 :                 ret = samldb_add_step(ac, samldb_find_for_defaultObjectCategory);
    1539       33704 :                 if (ret != LDB_SUCCESS) return ret;
    1540             : 
    1541             :                 /* -2 is not a valid objectClassCategory so it means the attribute wasn't present */
    1542       33704 :                 if (v == -2) {
    1543             :                         /* Windows 2003 does this*/
    1544         284 :                         ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "objectClassCategory", 0);
    1545         284 :                         if (ret != LDB_SUCCESS) {
    1546           0 :                                 return ret;
    1547             :                         }
    1548             :                 }
    1549       27786 :                 break;
    1550             :         }
    1551             : 
    1552      184328 :         case SAMLDB_TYPE_ATTRIBUTE: {
    1553      184328 :                 const char *lDAPDisplayName = NULL;
    1554       32978 :                 const struct ldb_val *rdn_value;
    1555       32978 :                 struct ldb_message_element *el;
    1556      184328 :                 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
    1557      184328 :                 if (rdn_value == NULL) {
    1558           0 :                         return ldb_operr(ldb);
    1559             :                 }
    1560      184328 :                 if (!ldb_msg_find_element(ac->msg, "lDAPDisplayName")) {
    1561             :                         /* the RDN has prefix "CN" */
    1562         106 :                         ret = ldb_msg_add_string(ac->msg, "lDAPDisplayName",
    1563         106 :                                 samdb_cn_to_lDAPDisplayName(ac->msg,
    1564         106 :                                                             (const char *) rdn_value->data));
    1565         106 :                         if (ret != LDB_SUCCESS) {
    1566           0 :                                 ldb_oom(ldb);
    1567           0 :                                 return ret;
    1568             :                         }
    1569             :                 }
    1570             : 
    1571      184328 :                 lDAPDisplayName = ldb_msg_find_attr_as_string(ac->msg,
    1572             :                                                               "lDAPDisplayName",
    1573             :                                                               NULL);
    1574      184328 :                 ret = ldb_valid_attr_name(lDAPDisplayName);
    1575      184328 :                 if (ret != 1 ||
    1576      184328 :                     lDAPDisplayName[0] == '*' ||
    1577      151350 :                     lDAPDisplayName[0] == '@')
    1578             :                 {
    1579           0 :                         return dsdb_module_werror(ac->module,
    1580             :                                                   LDB_ERR_UNWILLING_TO_PERFORM,
    1581             :                                                   WERR_DS_INVALID_LDAP_DISPLAY_NAME,
    1582             :                                                   "lDAPDisplayName is invalid");
    1583             :                 }
    1584             : 
    1585             :                 /* do not allow one to mark an attributeSchema as RODC filtered if it
    1586             :                  * is system-critical */
    1587      184328 :                 if (check_rodc_critical_attribute(ac->msg)) {
    1588           0 :                         ldb_asprintf_errstring(ldb,
    1589             :                                                "samldb: refusing schema add of %s - cannot combine critical attribute with RODC filtering",
    1590           0 :                                                ldb_dn_get_linearized(ac->msg->dn));
    1591           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    1592             :                 }
    1593             : 
    1594      184328 :                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
    1595             :                                                   "isSingleValued", "FALSE");
    1596      184328 :                 if (ret != LDB_SUCCESS) return ret;
    1597             : 
    1598      184328 :                 if (!ldb_msg_find_element(ac->msg, "schemaIDGUID")) {
    1599           0 :                         struct GUID guid;
    1600             :                         /* a new GUID */
    1601         263 :                         guid = GUID_random();
    1602         263 :                         ret = dsdb_msg_add_guid(ac->msg, &guid, "schemaIDGUID");
    1603         263 :                         if (ret != LDB_SUCCESS) {
    1604           0 :                                 ldb_oom(ldb);
    1605           0 :                                 return ret;
    1606             :                         }
    1607             :                 }
    1608             : 
    1609      184328 :                 el = ldb_msg_find_element(ac->msg, "attributeSyntax");
    1610      184328 :                 if (el) {
    1611             :                         /*
    1612             :                          * No need to scream if there isn't as we have code later on
    1613             :                          * that will take care of it.
    1614             :                          */
    1615      184328 :                         const struct dsdb_syntax *syntax = find_syntax_map_by_ad_oid((const char *)el->values[0].data);
    1616      184328 :                         if (!syntax) {
    1617           0 :                                 DEBUG(9, ("Can't find dsdb_syntax object for attributeSyntax %s\n",
    1618             :                                                 (const char *)el->values[0].data));
    1619             :                         } else {
    1620      184328 :                                 unsigned int v = ldb_msg_find_attr_as_uint(ac->msg, "oMSyntax", 0);
    1621      184328 :                                 const struct ldb_val *val = ldb_msg_find_ldb_val(ac->msg, "oMObjectClass");
    1622             : 
    1623      184328 :                                 if (v == 0) {
    1624           0 :                                         ret = samdb_msg_add_uint(ldb, ac->msg, ac->msg, "oMSyntax", syntax->oMSyntax);
    1625           0 :                                         if (ret != LDB_SUCCESS) {
    1626           0 :                                                 return ret;
    1627             :                                         }
    1628             :                                 }
    1629      184328 :                                 if (!val) {
    1630      158469 :                                         struct ldb_val val2 = ldb_val_dup(ldb, &syntax->oMObjectClass);
    1631      158469 :                                         if (val2.length > 0) {
    1632          59 :                                                 ret = ldb_msg_add_value(ac->msg, "oMObjectClass", &val2, NULL);
    1633          59 :                                                 if (ret != LDB_SUCCESS) {
    1634           0 :                                                         return ret;
    1635             :                                                 }
    1636             :                                         }
    1637             :                                 }
    1638             :                         }
    1639             :                 }
    1640             : 
    1641             :                 /* handle msDS-IntID attribute */
    1642      184328 :                 ret = samldb_add_handle_msDS_IntId(ac);
    1643      184328 :                 if (ret != LDB_SUCCESS) return ret;
    1644             : 
    1645      184310 :                 ret = samldb_add_step(ac, samldb_add_entry);
    1646      184310 :                 if (ret != LDB_SUCCESS) return ret;
    1647      151332 :                 break;
    1648             :         }
    1649             : 
    1650           0 :         default:
    1651           0 :                 ldb_asprintf_errstring(ldb, "Invalid entry type!");
    1652           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    1653       39962 :                 break;
    1654             :         }
    1655             : 
    1656      256691 :         return samldb_first_step(ac);
    1657             : }
    1658             : 
    1659        3857 : static int samldb_fill_foreignSecurityPrincipal_object(struct samldb_ctx *ac)
    1660             : {
    1661        3857 :         struct ldb_context *ldb = NULL;
    1662        3857 :         const struct ldb_val *rdn_value = NULL;
    1663        3857 :         struct ldb_message_element *sid_el = NULL;
    1664        3857 :         struct dom_sid *sid = NULL;
    1665        3857 :         struct ldb_control *as_system = NULL;
    1666        3857 :         struct ldb_control *provision = NULL;
    1667        3857 :         bool allowed = false;
    1668         660 :         int ret;
    1669             : 
    1670        3857 :         ldb = ldb_module_get_ctx(ac->module);
    1671             : 
    1672        3857 :         as_system = ldb_request_get_control(ac->req, LDB_CONTROL_AS_SYSTEM_OID);
    1673        3857 :         if (as_system != NULL) {
    1674          43 :                 allowed = true;
    1675             :         }
    1676             : 
    1677        3857 :         provision = ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID);
    1678        3857 :         if (provision != NULL) {
    1679        3812 :                 allowed = true;
    1680             :         }
    1681             : 
    1682        3857 :         sid_el = ldb_msg_find_element(ac->msg, "objectSid");
    1683             : 
    1684        3857 :         if (!allowed && sid_el == NULL) {
    1685           1 :                 return dsdb_module_werror(ac->module,
    1686             :                                 LDB_ERR_OBJECT_CLASS_VIOLATION,
    1687             :                                 WERR_DS_MISSING_REQUIRED_ATT,
    1688             :                                 "objectSid missing on foreignSecurityPrincipal");
    1689             :         }
    1690             : 
    1691        3856 :         if (!allowed) {
    1692           1 :                 return dsdb_module_werror(ac->module,
    1693             :                                 LDB_ERR_UNWILLING_TO_PERFORM,
    1694             :                                 WERR_DS_ILLEGAL_MOD_OPERATION,
    1695             :                                 "foreignSecurityPrincipal object not allowed");
    1696             :         }
    1697             : 
    1698        3855 :         if (sid_el != NULL) {
    1699        3810 :                 sid = samdb_result_dom_sid(ac->msg, ac->msg, "objectSid");
    1700        3810 :                 if (sid == NULL) {
    1701           0 :                         ldb_set_errstring(ldb,
    1702             :                                           "samldb: invalid objectSid!");
    1703           0 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
    1704             :                 }
    1705             :         }
    1706             : 
    1707        3195 :         if (sid == NULL) {
    1708          45 :                 rdn_value = ldb_dn_get_rdn_val(ac->msg->dn);
    1709          45 :                 if (rdn_value == NULL) {
    1710           0 :                         return ldb_operr(ldb);
    1711             :                 }
    1712          45 :                 sid = dom_sid_parse_talloc(ac->msg,
    1713          45 :                                            (const char *)rdn_value->data);
    1714          45 :                 if (sid == NULL) {
    1715           0 :                         ldb_set_errstring(ldb,
    1716             :                                           "samldb: No valid SID found in ForeignSecurityPrincipal CN!");
    1717           0 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
    1718             :                 }
    1719          45 :                 if (! samldb_msg_add_sid(ac->msg, "objectSid", sid)) {
    1720           0 :                         return ldb_operr(ldb);
    1721             :                 }
    1722             :         }
    1723             : 
    1724             :         /* finally proceed with adding the entry */
    1725        3855 :         ret = samldb_add_step(ac, samldb_add_entry);
    1726        3855 :         if (ret != LDB_SUCCESS) return ret;
    1727             : 
    1728        3855 :         return samldb_first_step(ac);
    1729             : }
    1730             : 
    1731      218032 : static int samldb_schema_info_update(struct samldb_ctx *ac)
    1732             : {
    1733       38896 :         int ret;
    1734       38896 :         struct ldb_context *ldb;
    1735       38896 :         struct dsdb_schema *schema;
    1736             : 
    1737             :         /* replicated update should always go through */
    1738      218032 :         if (ldb_request_get_control(ac->req,
    1739             :                                     DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
    1740           0 :                 return LDB_SUCCESS;
    1741             :         }
    1742             : 
    1743             :         /* do not update schemaInfo during provisioning */
    1744      218032 :         if (ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID)) {
    1745      177321 :                 return LDB_SUCCESS;
    1746             :         }
    1747             : 
    1748        1815 :         ldb = ldb_module_get_ctx(ac->module);
    1749        1815 :         schema = dsdb_get_schema(ldb, NULL);
    1750        1815 :         if (!schema) {
    1751           0 :                 ldb_debug_set(ldb, LDB_DEBUG_FATAL,
    1752             :                               "samldb_schema_info_update: no dsdb_schema loaded");
    1753           0 :                 DEBUG(0,(__location__ ": %s\n", ldb_errstring(ldb)));
    1754           0 :                 return ldb_operr(ldb);
    1755             :         }
    1756             : 
    1757        1815 :         ret = dsdb_module_schema_info_update(ac->module, schema,
    1758             :                                              DSDB_FLAG_NEXT_MODULE|
    1759             :                                              DSDB_FLAG_AS_SYSTEM,
    1760             :                                              ac->req);
    1761        1815 :         if (ret != LDB_SUCCESS) {
    1762           0 :                 ldb_asprintf_errstring(ldb,
    1763             :                                        "samldb_schema_info_update: dsdb_module_schema_info_update failed with %s",
    1764             :                                        ldb_errstring(ldb));
    1765           0 :                 return ret;
    1766             :         }
    1767             : 
    1768        1815 :         return LDB_SUCCESS;
    1769             : }
    1770             : 
    1771             : static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid);
    1772             : static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
    1773             :                                                    struct dom_sid *sid,
    1774             :                                                    uint32_t req_uac,
    1775             :                                                    uint32_t user_account_control,
    1776             :                                                    uint32_t user_account_control_old,
    1777             :                                                    bool is_computer_objectclass);
    1778             : 
    1779             : /*
    1780             :  * "Objectclass" trigger (MS-SAMR 3.1.1.8.1)
    1781             :  *
    1782             :  * Has to be invoked on "add" operations on "user", "computer" and
    1783             :  * "group" objects.
    1784             :  * ac->msg contains the "add"
    1785             :  * ac->type contains the object type (main objectclass)
    1786             :  */
    1787       38793 : static int samldb_objectclass_trigger(struct samldb_ctx *ac)
    1788             : {
    1789       38793 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    1790       38793 :         void *skip_allocate_sids = ldb_get_opaque(ldb,
    1791             :                                                   "skip_allocate_sids");
    1792        1066 :         struct ldb_message_element *el;
    1793        1066 :         struct dom_sid *sid;
    1794        1066 :         int ret;
    1795             : 
    1796             :         /* make sure that "sAMAccountType" is not specified */
    1797       38793 :         el = ldb_msg_find_element(ac->msg, "sAMAccountType");
    1798       38793 :         if (el != NULL) {
    1799           1 :                 ldb_set_errstring(ldb,
    1800             :                                   "samldb: sAMAccountType must not be specified!");
    1801           1 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1802             :         }
    1803             : 
    1804             :         /* Step 1: objectSid assignment */
    1805             : 
    1806             :         /* Don't allow the objectSid to be changed. But beside the RELAX
    1807             :          * control we have also to guarantee that it can always be set with
    1808             :          * SYSTEM permissions. This is needed for the "samba3sam" backend. */
    1809       38792 :         sid = samdb_result_dom_sid(ac, ac->msg, "objectSid");
    1810       43875 :         if ((sid != NULL) && (!dsdb_module_am_system(ac->module)) &&
    1811        5083 :             (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
    1812           0 :                 ldb_set_errstring(ldb,
    1813             :                                   "samldb: objectSid must not be specified!");
    1814           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    1815             :         }
    1816             : 
    1817             :         /* but generate a new SID when we do have an add operations */
    1818       38792 :         if ((sid == NULL) && (ac->req->operation == LDB_ADD) && !skip_allocate_sids) {
    1819       33651 :                 ret = samldb_add_step(ac, samldb_allocate_sid);
    1820       33651 :                 if (ret != LDB_SUCCESS) return ret;
    1821             :         }
    1822             : 
    1823       38792 :         switch(ac->type) {
    1824       30082 :         case SAMLDB_TYPE_USER: {
    1825         221 :                 uint32_t raw_uac;
    1826         221 :                 uint32_t user_account_control;
    1827         221 :                 bool is_computer_objectclass;
    1828       30082 :                 bool uac_generated = false, uac_add_flags = false;
    1829       30082 :                 uint32_t default_user_account_control = UF_NORMAL_ACCOUNT;
    1830             :                 /* Step 1.2: Default values */
    1831       30082 :                 ret = dsdb_user_obj_set_defaults(ldb, ac->msg, ac->req);
    1832       30082 :                 if (ret != LDB_SUCCESS) return ret;
    1833             : 
    1834         221 :                 is_computer_objectclass
    1835       60164 :                         = (samdb_find_attribute(ldb,
    1836       30082 :                                                  ac->msg,
    1837             :                                                 "objectclass",
    1838             :                                                 "computer")
    1839             :                            != NULL);
    1840             : 
    1841       30082 :                 if (is_computer_objectclass) {
    1842          94 :                         default_user_account_control
    1843        4121 :                                 = UF_WORKSTATION_TRUST_ACCOUNT;
    1844             :                 }
    1845             : 
    1846             : 
    1847             :                 /* On add operations we might need to generate a
    1848             :                  * "userAccountControl" (if it isn't specified). */
    1849       30082 :                 el = ldb_msg_find_element(ac->msg, "userAccountControl");
    1850       30082 :                 if (el == NULL) {
    1851       23937 :                         ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
    1852             :                                                  "userAccountControl",
    1853             :                                                  default_user_account_control);
    1854       23937 :                         if (ret != LDB_SUCCESS) {
    1855           0 :                                 return ret;
    1856             :                         }
    1857       23884 :                         uac_generated = true;
    1858       23884 :                         uac_add_flags = true;
    1859             :                 }
    1860             : 
    1861       30082 :                 el = ldb_msg_find_element(ac->msg, "userAccountControl");
    1862       30082 :                 SMB_ASSERT(el != NULL);
    1863             : 
    1864             :                 /* Step 1.3: "userAccountControl" -> "sAMAccountType" mapping */
    1865       30082 :                 user_account_control = ldb_msg_find_attr_as_uint(ac->msg,
    1866             :                                                                  "userAccountControl",
    1867             :                                                                  0);
    1868       30082 :                 raw_uac = user_account_control;
    1869             :                 /*
    1870             :                  * "userAccountControl" = 0 or missing one of
    1871             :                  * the types means "UF_NORMAL_ACCOUNT"
    1872             :                  * or "UF_WORKSTATION_TRUST_ACCOUNT" (if a computer).
    1873             :                  * See MS-SAMR 3.1.1.8.10 point 8
    1874             :                  */
    1875       30082 :                 if ((user_account_control & UF_ACCOUNT_TYPE_MASK) == 0) {
    1876           0 :                         user_account_control
    1877          30 :                                 = default_user_account_control
    1878             :                                 | user_account_control;
    1879          30 :                         uac_generated = true;
    1880             :                 }
    1881             : 
    1882             :                 /*
    1883             :                  * As per MS-SAMR 3.1.1.8.10 these flags have not to be set
    1884             :                  */
    1885       30082 :                 if ((user_account_control & UF_LOCKOUT) != 0) {
    1886           7 :                         user_account_control &= ~UF_LOCKOUT;
    1887           7 :                         uac_generated = true;
    1888             :                 }
    1889       30082 :                 if ((user_account_control & UF_PASSWORD_EXPIRED) != 0) {
    1890           7 :                         user_account_control &= ~UF_PASSWORD_EXPIRED;
    1891           7 :                         uac_generated = true;
    1892             :                 }
    1893             : 
    1894       30082 :                 ret = samldb_check_user_account_control_rules(ac, NULL,
    1895             :                                                               raw_uac,
    1896             :                                                               user_account_control,
    1897             :                                                               0,
    1898             :                                                               is_computer_objectclass);
    1899       30082 :                 if (ret != LDB_SUCCESS) {
    1900         109 :                         return ret;
    1901             :                 }
    1902             : 
    1903             :                 /*
    1904             :                  * Require, for non-admin modifications, a trailing $
    1905             :                  * for either objectclass=computer or a trust account
    1906             :                  * type in userAccountControl
    1907             :                  */
    1908       29973 :                 if ((user_account_control
    1909       29973 :                      & UF_TRUST_ACCOUNT_MASK) != 0) {
    1910        4078 :                         ac->need_trailing_dollar = true;
    1911             :                 }
    1912             : 
    1913       29973 :                 if (is_computer_objectclass) {
    1914        4079 :                         ac->need_trailing_dollar = true;
    1915             :                 }
    1916             : 
    1917             :                 /* add "sAMAccountType" attribute */
    1918       29973 :                 ret = dsdb_user_obj_set_account_type(ldb, ac->msg, user_account_control, NULL);
    1919       29973 :                 if (ret != LDB_SUCCESS) {
    1920           0 :                         return ret;
    1921             :                 }
    1922             : 
    1923             :                 /* "isCriticalSystemObject" might be set */
    1924       29973 :                 if (user_account_control &
    1925             :                     (UF_SERVER_TRUST_ACCOUNT | UF_PARTIAL_SECRETS_ACCOUNT)) {
    1926        1228 :                         ret = ldb_msg_add_string_flags(ac->msg, "isCriticalSystemObject",
    1927             :                                                        "TRUE", LDB_FLAG_MOD_REPLACE);
    1928        1228 :                         if (ret != LDB_SUCCESS) {
    1929           0 :                                 return ret;
    1930             :                         }
    1931       28745 :                 } else if (user_account_control & UF_WORKSTATION_TRUST_ACCOUNT) {
    1932        2779 :                         ret = ldb_msg_add_string_flags(ac->msg, "isCriticalSystemObject",
    1933             :                                                        "FALSE", LDB_FLAG_MOD_REPLACE);
    1934        2779 :                         if (ret != LDB_SUCCESS) {
    1935           0 :                                 return ret;
    1936             :                         }
    1937             :                 }
    1938             : 
    1939             :                 /* Step 1.4: "userAccountControl" -> "primaryGroupID" mapping */
    1940       29973 :                 if (!ldb_msg_find_element(ac->msg, "primaryGroupID")) {
    1941         199 :                         uint32_t rid;
    1942             : 
    1943       29845 :                         ret = dsdb_user_obj_set_primary_group_id(ldb, ac->msg, user_account_control, &rid);
    1944       29845 :                         if (ret != LDB_SUCCESS) {
    1945           0 :                                 return ret;
    1946             :                         }
    1947             :                         /*
    1948             :                          * Older AD deployments don't know about the
    1949             :                          * RODC group
    1950             :                          */
    1951       29845 :                         if (rid == DOMAIN_RID_READONLY_DCS) {
    1952         158 :                                 ret = samldb_prim_group_tester(ac, rid);
    1953         158 :                                 if (ret != LDB_SUCCESS) {
    1954           0 :                                         return ret;
    1955             :                                 }
    1956             :                         }
    1957             :                 }
    1958             : 
    1959             :                 /* Step 1.5: Add additional flags when needed */
    1960             :                 /* Obviously this is done when the "userAccountControl"
    1961             :                  * has been generated here (tested against Windows
    1962             :                  * Server) */
    1963       29973 :                 if (uac_generated) {
    1964       23975 :                         if (uac_add_flags) {
    1965       23937 :                                 user_account_control |= UF_ACCOUNTDISABLE;
    1966       23937 :                                 user_account_control |= UF_PASSWD_NOTREQD;
    1967             :                         }
    1968             : 
    1969       23975 :                         ret = samdb_msg_set_uint(ldb, ac->msg, ac->msg,
    1970             :                                                  "userAccountControl",
    1971             :                                                  user_account_control);
    1972       23975 :                         if (ret != LDB_SUCCESS) {
    1973           0 :                                 return ret;
    1974             :                         }
    1975             :                 }
    1976       29752 :                 break;
    1977             :         }
    1978             : 
    1979        8710 :         case SAMLDB_TYPE_GROUP: {
    1980         845 :                 const char *tempstr;
    1981             : 
    1982             :                 /* Step 2.2: Default values */
    1983        8710 :                 tempstr = talloc_asprintf(ac->msg, "%d",
    1984             :                                           GTYPE_SECURITY_GLOBAL_GROUP);
    1985        8710 :                 if (tempstr == NULL) return ldb_operr(ldb);
    1986        8710 :                 ret = samdb_find_or_add_attribute(ldb, ac->msg,
    1987             :                         "groupType", tempstr);
    1988        8710 :                 if (ret != LDB_SUCCESS) return ret;
    1989             : 
    1990             :                 /* Step 2.3: "groupType" -> "sAMAccountType" */
    1991        8710 :                 el = ldb_msg_find_element(ac->msg, "groupType");
    1992        8710 :                 if (el != NULL) {
    1993         845 :                         uint32_t group_type, account_type;
    1994             : 
    1995        8710 :                         group_type = ldb_msg_find_attr_as_uint(ac->msg,
    1996             :                                                                "groupType", 0);
    1997             : 
    1998             :                         /* The creation of builtin groups requires the
    1999             :                          * RELAX control */
    2000        8710 :                         if (group_type == GTYPE_SECURITY_BUILTIN_LOCAL_GROUP) {
    2001        2670 :                                 if (ldb_request_get_control(ac->req,
    2002             :                                                             LDB_CONTROL_RELAX_OID) == NULL) {
    2003           3 :                                         return LDB_ERR_UNWILLING_TO_PERFORM;
    2004             :                                 }
    2005             :                         }
    2006             : 
    2007        8707 :                         account_type = ds_gtype2atype(group_type);
    2008        8707 :                         if (account_type == 0) {
    2009           3 :                                 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
    2010           3 :                                 return LDB_ERR_UNWILLING_TO_PERFORM;
    2011             :                         }
    2012        8704 :                         ret = samdb_msg_add_uint_flags(ldb, ac->msg, ac->msg,
    2013             :                                                        "sAMAccountType",
    2014             :                                                        account_type,
    2015             :                                                        LDB_FLAG_MOD_REPLACE);
    2016        8704 :                         if (ret != LDB_SUCCESS) {
    2017           0 :                                 return ret;
    2018             :                         }
    2019             :                 }
    2020        7859 :                 break;
    2021             :         }
    2022             : 
    2023           0 :         default:
    2024           0 :                 ldb_asprintf_errstring(ldb,
    2025             :                                 "Invalid entry type!");
    2026           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    2027             :                 break;
    2028             :         }
    2029             : 
    2030       37611 :         return LDB_SUCCESS;
    2031             : }
    2032             : 
    2033             : /*
    2034             :  * "Primary group ID" trigger (MS-SAMR 3.1.1.8.2)
    2035             :  *
    2036             :  * Has to be invoked on "add" and "modify" operations on "user" and "computer"
    2037             :  * objects.
    2038             :  * ac->msg contains the "add"/"modify" message
    2039             :  */
    2040             : 
    2041         307 : static int samldb_prim_group_tester(struct samldb_ctx *ac, uint32_t rid)
    2042             : {
    2043         307 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    2044          22 :         struct dom_sid *sid;
    2045          22 :         struct ldb_result *res;
    2046          22 :         int ret;
    2047         307 :         const char * const noattrs[] = { NULL };
    2048             : 
    2049         307 :         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), rid);
    2050         307 :         if (sid == NULL) {
    2051           0 :                 return ldb_operr(ldb);
    2052             :         }
    2053             : 
    2054         307 :         ret = dsdb_module_search(ac->module, ac, &res,
    2055             :                                  ldb_get_default_basedn(ldb),
    2056             :                                  LDB_SCOPE_SUBTREE,
    2057             :                                  noattrs, DSDB_FLAG_NEXT_MODULE,
    2058             :                                  ac->req,
    2059             :                                  "(objectSid=%s)",
    2060             :                                  ldap_encode_ndr_dom_sid(ac, sid));
    2061         307 :         if (ret != LDB_SUCCESS) {
    2062           0 :                 return ret;
    2063             :         }
    2064         307 :         if (res->count != 1) {
    2065           0 :                 talloc_free(res);
    2066           0 :                 ldb_asprintf_errstring(ldb,
    2067             :                                        "Failed to find primary group with RID %u!",
    2068             :                                        rid);
    2069           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    2070             :         }
    2071         307 :         talloc_free(res);
    2072             : 
    2073         307 :         return LDB_SUCCESS;
    2074             : }
    2075             : 
    2076       30109 : static int samldb_prim_group_set(struct samldb_ctx *ac)
    2077             : {
    2078       30109 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    2079         221 :         uint32_t rid;
    2080             : 
    2081       30109 :         rid = ldb_msg_find_attr_as_uint(ac->msg, "primaryGroupID", (uint32_t) -1);
    2082       30109 :         if (rid == (uint32_t) -1) {
    2083             :                 /* we aren't affected of any primary group set */
    2084       29756 :                 return LDB_SUCCESS;
    2085             : 
    2086         154 :         } else if (!ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID)) {
    2087          26 :                 ldb_set_errstring(ldb,
    2088             :                                   "The primary group isn't settable on add operations!");
    2089          26 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    2090             :         }
    2091             : 
    2092         128 :         return samldb_prim_group_tester(ac, rid);
    2093             : }
    2094             : 
    2095         202 : static int samldb_prim_group_change(struct samldb_ctx *ac)
    2096             : {
    2097         202 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    2098         202 :         const char * const attrs[] = {
    2099             :                 "primaryGroupID",
    2100             :                 "memberOf",
    2101             :                 "userAccountControl",
    2102             :                 NULL };
    2103           2 :         struct ldb_result *res, *group_res;
    2104           2 :         struct ldb_message_element *el;
    2105           2 :         struct ldb_message *msg;
    2106         202 :         uint32_t search_flags =
    2107             :                 DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_EXTENDED_DN;
    2108           2 :         uint32_t prev_rid, new_rid, uac;
    2109           2 :         struct dom_sid *prev_sid, *new_sid;
    2110           2 :         struct ldb_dn *prev_prim_group_dn, *new_prim_group_dn;
    2111         202 :         const char *new_prim_group_dn_ext_str = NULL;
    2112         202 :         struct ldb_dn *user_dn = NULL;
    2113         202 :         const char *user_dn_ext_str = NULL;
    2114           2 :         int ret;
    2115         202 :         const char * const noattrs[] = { NULL };
    2116         202 :         const char * const group_type_attrs[] = { "groupType", NULL };
    2117           2 :         unsigned group_type;
    2118             : 
    2119         204 :         ret = dsdb_get_expected_new_values(ac,
    2120         202 :                                            ac->msg,
    2121             :                                            "primaryGroupID",
    2122             :                                            &el,
    2123         202 :                                            ac->req->operation);
    2124         202 :         if (ret != LDB_SUCCESS) {
    2125           0 :                 return ret;
    2126             :         }
    2127             : 
    2128         202 :         if (el == NULL) {
    2129             :                 /* we are not affected */
    2130           3 :                 return LDB_SUCCESS;
    2131             :         }
    2132             : 
    2133             :         /* Fetch information from the existing object */
    2134             : 
    2135         199 :         ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
    2136             :                                     search_flags, ac->req);
    2137         199 :         if (ret != LDB_SUCCESS) {
    2138           0 :                 return ret;
    2139             :         }
    2140         199 :         user_dn = res->msgs[0]->dn;
    2141         199 :         user_dn_ext_str = ldb_dn_get_extended_linearized(ac, user_dn, 1);
    2142         199 :         if (user_dn_ext_str == NULL) {
    2143           0 :                 return ldb_operr(ldb);
    2144             :         }
    2145             : 
    2146         199 :         uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
    2147             : 
    2148             :         /* Finds out the DN of the old primary group */
    2149             : 
    2150         199 :         prev_rid = ldb_msg_find_attr_as_uint(res->msgs[0], "primaryGroupID",
    2151             :                                              (uint32_t) -1);
    2152         199 :         if (prev_rid == (uint32_t) -1) {
    2153             :                 /* User objects do always have a mandatory "primaryGroupID"
    2154             :                  * attribute. If this doesn't exist then the object is of the
    2155             :                  * wrong type. This is the exact Windows error code */
    2156           3 :                 return LDB_ERR_OBJECT_CLASS_VIOLATION;
    2157             :         }
    2158             : 
    2159         196 :         prev_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), prev_rid);
    2160         196 :         if (prev_sid == NULL) {
    2161           0 :                 return ldb_operr(ldb);
    2162             :         }
    2163             : 
    2164             :         /* Finds out the DN of the new primary group
    2165             :          * Notice: in order to parse the primary group ID correctly we create
    2166             :          * a temporary message here. */
    2167             : 
    2168         196 :         msg = ldb_msg_new(ac->msg);
    2169         196 :         if (msg == NULL) {
    2170           0 :                 return ldb_module_oom(ac->module);
    2171             :         }
    2172         196 :         ret = ldb_msg_add(msg, el, 0);
    2173         196 :         if (ret != LDB_SUCCESS) {
    2174           0 :                 return ret;
    2175             :         }
    2176         196 :         new_rid = ldb_msg_find_attr_as_uint(msg, "primaryGroupID", (uint32_t) -1);
    2177         196 :         talloc_free(msg);
    2178         196 :         if (new_rid == (uint32_t) -1) {
    2179             :                 /* we aren't affected of any primary group change */
    2180           3 :                 return LDB_SUCCESS;
    2181             :         }
    2182             : 
    2183         193 :         if (prev_rid == new_rid) {
    2184          13 :                 return LDB_SUCCESS;
    2185             :         }
    2186             : 
    2187         180 :         if ((uac & UF_SERVER_TRUST_ACCOUNT) && new_rid != DOMAIN_RID_DCS) {
    2188           1 :                 ldb_asprintf_errstring(ldb,
    2189             :                         "%08X: samldb: UF_SERVER_TRUST_ACCOUNT requires "
    2190             :                         "primaryGroupID=%u!",
    2191           1 :                         W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
    2192             :                         DOMAIN_RID_DCS);
    2193           1 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    2194             :         }
    2195             : 
    2196         179 :         if ((uac & UF_PARTIAL_SECRETS_ACCOUNT) && new_rid != DOMAIN_RID_READONLY_DCS) {
    2197           1 :                 ldb_asprintf_errstring(ldb,
    2198             :                         "%08X: samldb: UF_PARTIAL_SECRETS_ACCOUNT requires "
    2199             :                         "primaryGroupID=%u!",
    2200           1 :                         W_ERROR_V(WERR_DS_CANT_MOD_PRIMARYGROUPID),
    2201             :                         DOMAIN_RID_READONLY_DCS);
    2202           1 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    2203             :         }
    2204             : 
    2205         178 :         ret = dsdb_module_search(ac->module, ac, &group_res,
    2206             :                                  ldb_get_default_basedn(ldb),
    2207             :                                  LDB_SCOPE_SUBTREE,
    2208             :                                  noattrs, search_flags,
    2209             :                                  ac->req,
    2210             :                                  "(objectSid=%s)",
    2211             :                                  ldap_encode_ndr_dom_sid(ac, prev_sid));
    2212         178 :         if (ret != LDB_SUCCESS) {
    2213           0 :                 return ret;
    2214             :         }
    2215         178 :         if (group_res->count != 1) {
    2216           0 :                 return ldb_operr(ldb);
    2217             :         }
    2218         178 :         prev_prim_group_dn = group_res->msgs[0]->dn;
    2219             : 
    2220         178 :         new_sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb), new_rid);
    2221         178 :         if (new_sid == NULL) {
    2222           0 :                 return ldb_operr(ldb);
    2223             :         }
    2224             : 
    2225         178 :         ret = dsdb_module_search(ac->module, ac, &group_res,
    2226             :                                  ldb_get_default_basedn(ldb),
    2227             :                                  LDB_SCOPE_SUBTREE,
    2228             :                                  group_type_attrs, search_flags,
    2229             :                                  ac->req,
    2230             :                                  "(objectSid=%s)",
    2231             :                                  ldap_encode_ndr_dom_sid(ac, new_sid));
    2232         178 :         if (ret != LDB_SUCCESS) {
    2233           0 :                 return ret;
    2234             :         }
    2235         178 :         if (group_res->count != 1) {
    2236             :                 /* Here we know if the specified new primary group candidate is
    2237             :                  * valid or not. */
    2238           3 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    2239             :         }
    2240         175 :         new_prim_group_dn = group_res->msgs[0]->dn;
    2241             : 
    2242             :         /* The new primary group must not be domain-local. */
    2243         175 :         group_type = ldb_msg_find_attr_as_uint(group_res->msgs[0], "groupType", 0);
    2244         175 :         if (group_type & GROUP_TYPE_RESOURCE_GROUP) {
    2245           3 :                 return dsdb_module_werror(ac->module,
    2246             :                                           LDB_ERR_UNWILLING_TO_PERFORM,
    2247             :                                           WERR_MEMBER_NOT_IN_GROUP,
    2248             :                                           "may not set resource group as primary group!");
    2249             :         }
    2250             : 
    2251         172 :         new_prim_group_dn_ext_str = ldb_dn_get_extended_linearized(ac,
    2252             :                                                         new_prim_group_dn, 1);
    2253         172 :         if (new_prim_group_dn_ext_str == NULL) {
    2254           0 :                 return ldb_operr(ldb);
    2255             :         }
    2256             : 
    2257             :         /* We need to be already a normal member of the new primary
    2258             :          * group in order to be successful. */
    2259         172 :         el = samdb_find_attribute(ldb, res->msgs[0], "memberOf",
    2260             :                                   new_prim_group_dn_ext_str);
    2261         172 :         if (el == NULL) {
    2262           3 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    2263             :         }
    2264             : 
    2265             :         /* Remove the "member" attribute on the new primary group */
    2266         169 :         msg = ldb_msg_new(ac->msg);
    2267         169 :         if (msg == NULL) {
    2268           0 :                 return ldb_module_oom(ac->module);
    2269             :         }
    2270         169 :         msg->dn = new_prim_group_dn;
    2271             : 
    2272         169 :         ret = samdb_msg_add_delval(ldb, msg, msg, "member", user_dn_ext_str);
    2273         169 :         if (ret != LDB_SUCCESS) {
    2274           0 :                 return ret;
    2275             :         }
    2276             : 
    2277         169 :         ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
    2278         169 :         if (ret != LDB_SUCCESS) {
    2279           0 :                 return ret;
    2280             :         }
    2281         169 :         talloc_free(msg);
    2282             : 
    2283             :         /* Add a "member" attribute for the previous primary group */
    2284         169 :         msg = ldb_msg_new(ac->msg);
    2285         169 :         if (msg == NULL) {
    2286           0 :                 return ldb_module_oom(ac->module);
    2287             :         }
    2288         169 :         msg->dn = prev_prim_group_dn;
    2289             : 
    2290         169 :         ret = samdb_msg_add_addval(ldb, msg, msg, "member", user_dn_ext_str);
    2291         169 :         if (ret != LDB_SUCCESS) {
    2292           0 :                 return ret;
    2293             :         }
    2294             : 
    2295         169 :         ret = dsdb_module_modify(ac->module, msg, DSDB_FLAG_NEXT_MODULE, ac->req);
    2296         169 :         if (ret != LDB_SUCCESS) {
    2297           0 :                 return ret;
    2298             :         }
    2299         169 :         talloc_free(msg);
    2300             : 
    2301         169 :         return LDB_SUCCESS;
    2302             : }
    2303             : 
    2304       30311 : static int samldb_prim_group_trigger(struct samldb_ctx *ac)
    2305             : {
    2306         223 :         int ret;
    2307             : 
    2308       30311 :         if (ac->req->operation == LDB_ADD) {
    2309       30109 :                 ret = samldb_prim_group_set(ac);
    2310             :         } else {
    2311         202 :                 ret = samldb_prim_group_change(ac);
    2312             :         }
    2313             : 
    2314       30311 :         return ret;
    2315             : }
    2316             : 
    2317       46060 : static int samldb_check_user_account_control_invariants(struct samldb_ctx *ac,
    2318             :                                                     uint32_t user_account_control)
    2319             : {
    2320         330 :         size_t i;
    2321       46060 :         int ret = 0;
    2322       46060 :         bool need_check = false;
    2323         330 :         const struct uac_to_guid {
    2324             :                 uint32_t uac;
    2325             :                 bool never;
    2326             :                 uint32_t needs;
    2327             :                 uint32_t not_with;
    2328             :                 const char *error_string;
    2329       46060 :         } map[] = {
    2330             :                 {
    2331             :                         .uac = UF_TEMP_DUPLICATE_ACCOUNT,
    2332             :                         .never = true,
    2333             :                         .error_string = "Updating the UF_TEMP_DUPLICATE_ACCOUNT flag is never allowed"
    2334             :                 },
    2335             :                 {
    2336             :                         .uac = UF_PARTIAL_SECRETS_ACCOUNT,
    2337             :                         .needs = UF_WORKSTATION_TRUST_ACCOUNT,
    2338             :                         .error_string = "Setting UF_PARTIAL_SECRETS_ACCOUNT only permitted with UF_WORKSTATION_TRUST_ACCOUNT"
    2339             :                 },
    2340             :                 {
    2341             :                         .uac = UF_TRUSTED_FOR_DELEGATION,
    2342             :                         .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
    2343             :                         .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
    2344             :                 },
    2345             :                 {
    2346             :                         .uac = UF_NORMAL_ACCOUNT,
    2347             :                         .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_NORMAL_ACCOUNT,
    2348             :                         .error_string = "Setting more than one account type not permitted"
    2349             :                 },
    2350             :                 {
    2351             :                         .uac = UF_WORKSTATION_TRUST_ACCOUNT,
    2352             :                         .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_WORKSTATION_TRUST_ACCOUNT,
    2353             :                         .error_string = "Setting more than one account type not permitted"
    2354             :                 },
    2355             :                 {
    2356             :                         .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
    2357             :                         .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_INTERDOMAIN_TRUST_ACCOUNT,
    2358             :                         .error_string = "Setting more than one account type not permitted"
    2359             :                 },
    2360             :                 {
    2361             :                         .uac = UF_SERVER_TRUST_ACCOUNT,
    2362             :                         .not_with = UF_ACCOUNT_TYPE_MASK & ~UF_SERVER_TRUST_ACCOUNT,
    2363             :                         .error_string = "Setting more than one account type not permitted"
    2364             :                 },
    2365             :                 {
    2366             :                         .uac = UF_TRUSTED_FOR_DELEGATION,
    2367             :                         .not_with = UF_PARTIAL_SECRETS_ACCOUNT,
    2368             :                         .error_string = "Setting UF_TRUSTED_FOR_DELEGATION not allowed with UF_PARTIAL_SECRETS_ACCOUNT"
    2369             :                 }
    2370             :         };
    2371             : 
    2372      188495 :         for (i = 0; i < ARRAY_SIZE(map); i++) {
    2373      188495 :                 if (user_account_control & map[i].uac) {
    2374       45730 :                         need_check = true;
    2375       45730 :                         break;
    2376             :                 }
    2377             :         }
    2378       46060 :         if (need_check == false) {
    2379           0 :                 return LDB_SUCCESS;
    2380             :         }
    2381             : 
    2382      414049 :         for (i = 0; i < ARRAY_SIZE(map); i++) {
    2383      368057 :                 uint32_t this_uac = user_account_control & map[i].uac;
    2384      368057 :                 if (this_uac != 0) {
    2385       48276 :                         if (map[i].never) {
    2386          16 :                                 ret = LDB_ERR_OTHER;
    2387          16 :                                 break;
    2388       48260 :                         } else if (map[i].needs != 0) {
    2389         439 :                                 if ((map[i].needs & user_account_control) == 0) {
    2390          51 :                                         ret = LDB_ERR_OTHER;
    2391          51 :                                         break;
    2392             :                                 }
    2393       47821 :                         } else if (map[i].not_with != 0) {
    2394       47821 :                                 if ((map[i].not_with & user_account_control) != 0) {
    2395           1 :                                         ret = LDB_ERR_OTHER;
    2396           1 :                                         break;
    2397             :                                 }
    2398             :                         }
    2399             :                 }
    2400             :         }
    2401       46060 :         if (ret != LDB_SUCCESS) {
    2402          68 :                 switch (ac->req->operation) {
    2403           7 :                 case LDB_ADD:
    2404           7 :                         ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    2405             :                                                "Failed to add %s: %s",
    2406           7 :                                                ldb_dn_get_linearized(ac->msg->dn),
    2407           7 :                                                map[i].error_string);
    2408           7 :                         break;
    2409          61 :                 case LDB_MODIFY:
    2410          61 :                         ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    2411             :                                                "Failed to modify %s: %s",
    2412          61 :                                                ldb_dn_get_linearized(ac->msg->dn),
    2413          61 :                                                map[i].error_string);
    2414          61 :                         break;
    2415           0 :                 default:
    2416           0 :                         return ldb_module_operr(ac->module);
    2417             :                 }
    2418             :         }
    2419       45730 :         return ret;
    2420             : }
    2421             : 
    2422             : /*
    2423             :  * It would be best if these rules apply, always, but for now they
    2424             :  * apply only to non-admins
    2425             :  */
    2426       45992 : static int samldb_check_user_account_control_objectclass_invariants(
    2427             :         struct samldb_ctx *ac,
    2428             :         uint32_t user_account_control,
    2429             :         uint32_t user_account_control_old,
    2430             :         bool is_computer_objectclass)
    2431             : {
    2432       45992 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    2433             : 
    2434       45992 :         uint32_t old_ufa = user_account_control_old & UF_ACCOUNT_TYPE_MASK;
    2435       45992 :         uint32_t new_ufa = user_account_control & UF_ACCOUNT_TYPE_MASK;
    2436             : 
    2437       45992 :         uint32_t old_rodc = user_account_control_old & UF_PARTIAL_SECRETS_ACCOUNT;
    2438       45992 :         uint32_t new_rodc = user_account_control & UF_PARTIAL_SECRETS_ACCOUNT;
    2439             : 
    2440         330 :         bool is_admin;
    2441         330 :         struct security_token *user_token
    2442       45992 :                 = acl_user_token(ac->module);
    2443       45992 :         if (user_token == NULL) {
    2444           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2445             :         }
    2446             : 
    2447         330 :         is_admin
    2448       45992 :                 = security_token_has_builtin_administrators(user_token);
    2449             : 
    2450             : 
    2451             :         /*
    2452             :          * We want to allow changes to (eg) disable an account
    2453             :          * that was created wrong, only checking the
    2454             :          * objectclass if the account type changes.
    2455             :          */
    2456       45992 :         if (old_ufa == new_ufa && old_rodc == new_rodc) {
    2457       15484 :                 return LDB_SUCCESS;
    2458             :         }
    2459             : 
    2460       30399 :         switch (new_ufa) {
    2461       26007 :         case UF_NORMAL_ACCOUNT:
    2462       26007 :                 if (is_computer_objectclass && !is_admin) {
    2463          39 :                         ldb_asprintf_errstring(ldb,
    2464             :                                 "%08X: samldb: UF_NORMAL_ACCOUNT "
    2465             :                                 "requires objectclass 'user' not 'computer'!",
    2466          39 :                                 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
    2467          39 :                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
    2468             :                 }
    2469       25841 :                 break;
    2470             : 
    2471          87 :         case UF_INTERDOMAIN_TRUST_ACCOUNT:
    2472          87 :                 if (is_computer_objectclass) {
    2473           8 :                         ldb_asprintf_errstring(ldb,
    2474             :                                 "%08X: samldb: UF_INTERDOMAIN_TRUST_ACCOUNT "
    2475             :                                 "requires objectclass 'user' not 'computer'!",
    2476           8 :                                 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
    2477           8 :                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
    2478             :                 }
    2479          79 :                 break;
    2480             : 
    2481        3137 :         case UF_WORKSTATION_TRUST_ACCOUNT:
    2482        3137 :                 if (!is_computer_objectclass) {
    2483             :                         /*
    2484             :                          * Modify of a user account account into a
    2485             :                          * workstation without objectclass computer
    2486             :                          * as an admin is still permitted, but not
    2487             :                          * to make an RODC
    2488             :                          */
    2489          70 :                         if (is_admin
    2490          47 :                             && ac->req->operation == LDB_MODIFY
    2491          25 :                             && new_rodc == 0) {
    2492          22 :                                 break;
    2493             :                         }
    2494          48 :                         ldb_asprintf_errstring(ldb,
    2495             :                                 "%08X: samldb: UF_WORKSTATION_TRUST_ACCOUNT "
    2496             :                                 "requires objectclass 'computer'!",
    2497          48 :                                 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
    2498          48 :                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
    2499             :                 }
    2500        3031 :                 break;
    2501             : 
    2502        1168 :         case UF_SERVER_TRUST_ACCOUNT:
    2503        1168 :                 if (!is_computer_objectclass) {
    2504          38 :                         ldb_asprintf_errstring(ldb,
    2505             :                                 "%08X: samldb: UF_SERVER_TRUST_ACCOUNT "
    2506             :                                 "requires objectclass 'computer'!",
    2507          38 :                                 W_ERROR_V(WERR_DS_MACHINE_ACCOUNT_CREATED_PRENT4));
    2508          38 :                         return LDB_ERR_OBJECT_CLASS_VIOLATION;
    2509             :                 }
    2510        1072 :                 break;
    2511             : 
    2512           0 :         default:
    2513           0 :                 ldb_asprintf_errstring(ldb,
    2514             :                         "%08X: samldb: invalid userAccountControl[0x%08X]",
    2515           0 :                         W_ERROR_V(WERR_INVALID_PARAMETER),
    2516             :                                        user_account_control);
    2517           0 :                 return LDB_ERR_OTHER;
    2518             :         }
    2519       30045 :         return LDB_SUCCESS;
    2520             : }
    2521             : 
    2522       43795 : static int samldb_get_domain_secdesc_and_oc(struct samldb_ctx *ac,
    2523             :                                             struct security_descriptor **domain_sd,
    2524             :                                             const struct dsdb_class **objectclass)
    2525             : {
    2526       43795 :         const char * const sd_attrs[] = {"ntSecurityDescriptor", "objectClass", NULL};
    2527         233 :         struct ldb_result *res;
    2528       43795 :         struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
    2529       43795 :         const struct dsdb_schema *schema = NULL;
    2530       43795 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    2531       43795 :         int ret = dsdb_module_search_dn(ac->module, ac, &res,
    2532             :                                         domain_dn,
    2533             :                                         sd_attrs,
    2534             :                                         DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
    2535             :                                         ac->req);
    2536       43795 :         if (ret != LDB_SUCCESS) {
    2537           0 :                 return ret;
    2538             :         }
    2539       43795 :         if (res->count != 1) {
    2540           0 :                 return ldb_module_operr(ac->module);
    2541             :         }
    2542             : 
    2543       43795 :         schema = dsdb_get_schema(ldb, ac->req);
    2544       43795 :         if (!schema) {
    2545           0 :                 return ldb_module_operr(ac->module);;
    2546             :         }
    2547       43795 :         *objectclass = dsdb_get_structural_oc_from_msg(schema, res->msgs[0]);
    2548       43795 :         return dsdb_get_sd_from_ldb_message(ldb_module_get_ctx(ac->module),
    2549       43795 :                                             ac, res->msgs[0], domain_sd);
    2550             : 
    2551             : }
    2552             : 
    2553             : /**
    2554             :  * Validate that the restriction in point 5 of MS-SAMR 3.1.1.8.10 userAccountControl is honoured
    2555             :  *
    2556             :  */
    2557       45859 : static int samldb_check_user_account_control_acl(struct samldb_ctx *ac,
    2558             :                                                  struct dom_sid *sid,
    2559             :                                                  uint32_t user_account_control,
    2560             :                                                  uint32_t user_account_control_old)
    2561             : {
    2562         330 :         size_t i;
    2563       45859 :         int ret = 0;
    2564       45859 :         bool need_acl_check = false;
    2565         330 :         struct security_token *user_token;
    2566         330 :         struct security_descriptor *domain_sd;
    2567       45859 :         const struct dsdb_class *objectclass = NULL;
    2568         330 :         const struct uac_to_guid {
    2569             :                 uint32_t uac;
    2570             :                 uint32_t priv_to_change_from;
    2571             :                 const char *oid;
    2572             :                 const char *guid;
    2573             :                 enum sec_privilege privilege;
    2574             :                 bool delete_is_privileged;
    2575             :                 bool admin_required;
    2576             :                 const char *error_string;
    2577       45859 :         } map[] = {
    2578             :                 {
    2579             :                         .uac = UF_PASSWD_NOTREQD,
    2580             :                         .guid = GUID_DRS_UPDATE_PASSWORD_NOT_REQUIRED_BIT,
    2581             :                         .error_string = "Adding the UF_PASSWD_NOTREQD bit in userAccountControl requires the Update-Password-Not-Required-Bit right that was not given on the Domain object"
    2582             :                 },
    2583             :                 {
    2584             :                         .uac = UF_DONT_EXPIRE_PASSWD,
    2585             :                         .guid = GUID_DRS_UNEXPIRE_PASSWORD,
    2586             :                         .error_string = "Adding the UF_DONT_EXPIRE_PASSWD bit in userAccountControl requires the Unexpire-Password right that was not given on the Domain object"
    2587             :                 },
    2588             :                 {
    2589             :                         .uac = UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED,
    2590             :                         .guid = GUID_DRS_ENABLE_PER_USER_REVERSIBLY_ENCRYPTED_PASSWORD,
    2591             :                         .error_string = "Adding the UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED bit in userAccountControl requires the Enable-Per-User-Reversibly-Encrypted-Password right that was not given on the Domain object"
    2592             :                 },
    2593             :                 {
    2594             :                         .uac = UF_SERVER_TRUST_ACCOUNT,
    2595             :                         .guid = GUID_DRS_DS_INSTALL_REPLICA,
    2596             :                         .error_string = "Adding the UF_SERVER_TRUST_ACCOUNT bit in userAccountControl requires the DS-Install-Replica right that was not given on the Domain object"
    2597             :                 },
    2598             :                 {
    2599             :                         .uac = UF_PARTIAL_SECRETS_ACCOUNT,
    2600             :                         .guid = GUID_DRS_DS_INSTALL_REPLICA,
    2601             :                         .error_string = "Adding the UF_PARTIAL_SECRETS_ACCOUNT bit in userAccountControl requires the DS-Install-Replica right that was not given on the Domain object"
    2602             :                 },
    2603             :                 {
    2604             :                         .uac = UF_WORKSTATION_TRUST_ACCOUNT,
    2605             :                         .priv_to_change_from = UF_NORMAL_ACCOUNT,
    2606             :                         .error_string = "Swapping UF_NORMAL_ACCOUNT to UF_WORKSTATION_TRUST_ACCOUNT requires the user to be a member of the domain admins group"
    2607             :                 },
    2608             :                 {
    2609             :                         .uac = UF_NORMAL_ACCOUNT,
    2610             :                         .priv_to_change_from = UF_WORKSTATION_TRUST_ACCOUNT,
    2611             :                         .error_string = "Swapping UF_WORKSTATION_TRUST_ACCOUNT to UF_NORMAL_ACCOUNT requires the user to be a member of the domain admins group"
    2612             :                 },
    2613             :                 {
    2614             :                         .uac = UF_INTERDOMAIN_TRUST_ACCOUNT,
    2615             :                         .oid = DSDB_CONTROL_PERMIT_INTERDOMAIN_TRUST_UAC_OID,
    2616             :                         .error_string = "Updating the UF_INTERDOMAIN_TRUST_ACCOUNT bit in userAccountControl is not permitted over LDAP.  This bit is restricted to the LSA CreateTrustedDomain interface",
    2617             :                         .delete_is_privileged = true
    2618             :                 },
    2619             :                 {
    2620             :                         .uac = UF_TRUSTED_FOR_DELEGATION,
    2621             :                         .privilege = SEC_PRIV_ENABLE_DELEGATION,
    2622             :                         .delete_is_privileged = true,
    2623             :                         .error_string = "Updating the UF_TRUSTED_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
    2624             :                 },
    2625             :                 {
    2626             :                         .uac = UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION,
    2627             :                         .privilege = SEC_PRIV_ENABLE_DELEGATION,
    2628             :                         .delete_is_privileged = true,
    2629             :                         .error_string = "Updating the UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION bit in userAccountControl is not permitted without the SeEnableDelegationPrivilege"
    2630             :                 }
    2631             : 
    2632             :         };
    2633             : 
    2634       45859 :         if (dsdb_module_am_system(ac->module)) {
    2635        2041 :                 return LDB_SUCCESS;
    2636             :         }
    2637             : 
    2638      286971 :         for (i = 0; i < ARRAY_SIZE(map); i++) {
    2639      286971 :                 if (user_account_control & map[i].uac) {
    2640       43488 :                         need_acl_check = true;
    2641       43488 :                         break;
    2642             :                 }
    2643             :         }
    2644       43721 :         if (need_acl_check == false) {
    2645           0 :                 return LDB_SUCCESS;
    2646             :         }
    2647             : 
    2648       43721 :         user_token = acl_user_token(ac->module);
    2649       43721 :         if (user_token == NULL) {
    2650           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2651             :         }
    2652             : 
    2653       43721 :         ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass);
    2654       43721 :         if (ret != LDB_SUCCESS) {
    2655           0 :                 return ret;
    2656             :         }
    2657             : 
    2658      480583 :         for (i = 0; i < ARRAY_SIZE(map); i++) {
    2659      436945 :                 uint32_t this_uac_new = user_account_control & map[i].uac;
    2660      436945 :                 uint32_t this_uac_old = user_account_control_old & map[i].uac;
    2661      436945 :                 if (this_uac_new != this_uac_old) {
    2662       45518 :                         if (this_uac_old != 0) {
    2663       13985 :                                 if (map[i].delete_is_privileged == false) {
    2664       13971 :                                         continue;
    2665             :                                 }
    2666             :                         }
    2667       31547 :                         if (map[i].oid) {
    2668          71 :                                 struct ldb_control *control = ldb_request_get_control(ac->req, map[i].oid);
    2669          71 :                                 if (control == NULL) {
    2670           8 :                                         ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2671             :                                 }
    2672       31476 :                         } else if (map[i].privilege != SEC_PRIV_INVALID) {
    2673         792 :                                 bool have_priv = security_token_has_privilege(user_token,
    2674         770 :                                                                               map[i].privilege);
    2675         792 :                                 if (have_priv == false) {
    2676          32 :                                         ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2677             :                                 }
    2678       30684 :                         } else if (map[i].priv_to_change_from & user_account_control_old) {
    2679         120 :                                 bool is_admin = security_token_has_builtin_administrators(user_token);
    2680         120 :                                 if (is_admin == false) {
    2681           7 :                                         ret = LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    2682             :                                 }
    2683       30564 :                         } else if (map[i].guid) {
    2684        2950 :                                 ret = acl_check_extended_right(ac,
    2685             :                                                                ac->module,
    2686             :                                                                ac->req,
    2687             :                                                                objectclass,
    2688             :                                                                domain_sd,
    2689             :                                                                user_token,
    2690        2776 :                                                                map[i].guid,
    2691             :                                                                SEC_ADS_CONTROL_ACCESS,
    2692             :                                                                sid);
    2693             :                         } else {
    2694       27511 :                                 ret = LDB_SUCCESS;
    2695             :                         }
    2696       31444 :                         if (ret != LDB_SUCCESS) {
    2697          83 :                                 break;
    2698             :                         }
    2699             :                 }
    2700             :         }
    2701       43721 :         if (ret == LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    2702          83 :                 switch (ac->req->operation) {
    2703          33 :                 case LDB_ADD:
    2704          33 :                         ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    2705             :                                                "Failed to add %s: %s",
    2706          33 :                                                ldb_dn_get_linearized(ac->msg->dn),
    2707          33 :                                                map[i].error_string);
    2708          33 :                         break;
    2709          50 :                 case LDB_MODIFY:
    2710          50 :                         ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    2711             :                                                "Failed to modify %s: %s",
    2712          50 :                                                ldb_dn_get_linearized(ac->msg->dn),
    2713          50 :                                                map[i].error_string);
    2714          50 :                         break;
    2715           0 :                 default:
    2716           0 :                         return ldb_module_operr(ac->module);
    2717             :                 }
    2718          83 :                 if (map[i].guid) {
    2719           0 :                         struct ldb_dn *domain_dn
    2720          36 :                                 = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
    2721          36 :                         dsdb_acl_debug(domain_sd, acl_user_token(ac->module),
    2722             :                                        domain_dn,
    2723             :                                        true,
    2724             :                                        10);
    2725             :                 }
    2726             :         }
    2727       43488 :         return ret;
    2728             : }
    2729             : 
    2730       46060 : static int samldb_check_user_account_control_rules(struct samldb_ctx *ac,
    2731             :                                                    struct dom_sid *sid,
    2732             :                                                    uint32_t req_uac,
    2733             :                                                    uint32_t user_account_control,
    2734             :                                                    uint32_t user_account_control_old,
    2735             :                                                    bool is_computer_objectclass)
    2736             : {
    2737         330 :         int ret;
    2738       46060 :         struct dsdb_control_password_user_account_control *uac = NULL;
    2739             : 
    2740       46060 :         ret = samldb_check_user_account_control_invariants(ac, user_account_control);
    2741       46060 :         if (ret != LDB_SUCCESS) {
    2742          68 :                 return ret;
    2743             :         }
    2744       45992 :         ret = samldb_check_user_account_control_objectclass_invariants(ac,
    2745             :                                                                        user_account_control,
    2746             :                                                                        user_account_control_old,
    2747             :                                                                        is_computer_objectclass);
    2748       45992 :         if (ret != LDB_SUCCESS) {
    2749         133 :                 return ret;
    2750             :         }
    2751             : 
    2752       45859 :         ret = samldb_check_user_account_control_acl(ac, sid, user_account_control, user_account_control_old);
    2753       45859 :         if (ret != LDB_SUCCESS) {
    2754          83 :                 return ret;
    2755             :         }
    2756             : 
    2757       45776 :         uac = talloc_zero(ac->req,
    2758             :                           struct dsdb_control_password_user_account_control);
    2759       45776 :         if (uac == NULL) {
    2760           0 :                 return ldb_module_oom(ac->module);
    2761             :         }
    2762             : 
    2763       45776 :         uac->req_flags = req_uac;
    2764       45776 :         uac->old_flags = user_account_control_old;
    2765       45776 :         uac->new_flags = user_account_control;
    2766             : 
    2767       45776 :         ret = ldb_request_add_control(ac->req,
    2768             :                                 DSDB_CONTROL_PASSWORD_USER_ACCOUNT_CONTROL_OID,
    2769             :                                 false, uac);
    2770       45776 :         if (ret != LDB_SUCCESS) {
    2771           0 :                 return ret;
    2772             :         }
    2773             : 
    2774       45446 :         return ret;
    2775             : }
    2776             : 
    2777             : 
    2778             : /**
    2779             :  * This function is called on LDB modify operations. It performs some additions/
    2780             :  * replaces on the current LDB message when "userAccountControl" changes.
    2781             :  */
    2782       15984 : static int samldb_user_account_control_change(struct samldb_ctx *ac)
    2783             : {
    2784       15984 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    2785         109 :         uint32_t old_uac;
    2786         109 :         uint32_t new_uac;
    2787         109 :         uint32_t raw_uac;
    2788         109 :         uint32_t old_ufa;
    2789         109 :         uint32_t new_ufa;
    2790         109 :         uint32_t old_uac_computed;
    2791         109 :         uint32_t clear_uac;
    2792         109 :         uint32_t old_atype;
    2793         109 :         uint32_t new_atype;
    2794         109 :         uint32_t old_pgrid;
    2795         109 :         uint32_t new_pgrid;
    2796         109 :         NTTIME old_lockoutTime;
    2797         109 :         struct ldb_message_element *el;
    2798         109 :         struct ldb_val *val;
    2799         109 :         struct ldb_val computer_val;
    2800         109 :         struct ldb_message *tmp_msg;
    2801         109 :         struct dom_sid *sid;
    2802         109 :         int ret;
    2803         109 :         struct ldb_result *res;
    2804       15984 :         const char * const attrs[] = {
    2805             :                 "objectClass",
    2806             :                 "isCriticalSystemObject",
    2807             :                 "userAccountControl",
    2808             :                 "msDS-User-Account-Control-Computed",
    2809             :                 "lockoutTime",
    2810             :                 "objectSid",
    2811             :                 NULL
    2812             :         };
    2813       15984 :         bool is_computer_objectclass = false;
    2814       15984 :         bool old_is_critical = false;
    2815       15984 :         bool new_is_critical = false;
    2816             : 
    2817       16093 :         ret = dsdb_get_expected_new_values(ac,
    2818       15984 :                                            ac->msg,
    2819             :                                            "userAccountControl",
    2820             :                                            &el,
    2821       15984 :                                            ac->req->operation);
    2822       15984 :         if (ret != LDB_SUCCESS) {
    2823           0 :                 return ret;
    2824             :         }
    2825             : 
    2826       15984 :         if (el == NULL || el->num_values == 0) {
    2827           6 :                 ldb_asprintf_errstring(ldb,
    2828             :                         "%08X: samldb: 'userAccountControl' can't be deleted!",
    2829           6 :                         W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
    2830           6 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    2831             :         }
    2832             : 
    2833             :         /* Create a temporary message for fetching the "userAccountControl" */
    2834       15978 :         tmp_msg = ldb_msg_new(ac->msg);
    2835       15978 :         if (tmp_msg == NULL) {
    2836           0 :                 return ldb_module_oom(ac->module);
    2837             :         }
    2838       15978 :         ret = ldb_msg_add(tmp_msg, el, 0);
    2839       15978 :         if (ret != LDB_SUCCESS) {
    2840           0 :                 return ret;
    2841             :         }
    2842       15978 :         raw_uac = ldb_msg_find_attr_as_uint(tmp_msg,
    2843             :                                             "userAccountControl",
    2844             :                                             0);
    2845       15978 :         talloc_free(tmp_msg);
    2846             :         /*
    2847             :          * UF_LOCKOUT, UF_PASSWD_CANT_CHANGE and UF_PASSWORD_EXPIRED
    2848             :          * are only generated and not stored. We ignore them almost
    2849             :          * completely, along with unknown bits and UF_SCRIPT.
    2850             :          *
    2851             :          * The only exception is ACB_AUTOLOCK, which features in
    2852             :          * clear_acb when the bit is cleared in this modify operation.
    2853             :          *
    2854             :          * MS-SAMR 2.2.1.13 UF_FLAG Codes states that some bits are
    2855             :          * ignored by clients and servers
    2856             :          */
    2857       15978 :         new_uac = raw_uac & UF_SETTABLE_BITS;
    2858             : 
    2859             :         /* Fetch the old "userAccountControl" and "objectClass" */
    2860       15978 :         ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
    2861             :                                     DSDB_FLAG_NEXT_MODULE, ac->req);
    2862       15978 :         if (ret != LDB_SUCCESS) {
    2863           0 :                 return ret;
    2864             :         }
    2865       15978 :         old_uac = ldb_msg_find_attr_as_uint(res->msgs[0], "userAccountControl", 0);
    2866       15978 :         if (old_uac == 0) {
    2867           0 :                 return ldb_operr(ldb);
    2868             :         }
    2869       15978 :         old_uac_computed = ldb_msg_find_attr_as_uint(res->msgs[0],
    2870             :                                                      "msDS-User-Account-Control-Computed", 0);
    2871       15978 :         old_lockoutTime = ldb_msg_find_attr_as_int64(res->msgs[0],
    2872             :                                                      "lockoutTime", 0);
    2873       15978 :         old_is_critical = ldb_msg_find_attr_as_bool(res->msgs[0],
    2874             :                                                     "isCriticalSystemObject", 0);
    2875             :         /*
    2876             :          * When we do not have objectclass "computer" we cannot
    2877             :          * switch to a workstation or (RO)DC
    2878             :          */
    2879       15978 :         el = ldb_msg_find_element(res->msgs[0], "objectClass");
    2880       15978 :         if (el == NULL) {
    2881           0 :                 return ldb_operr(ldb);
    2882             :         }
    2883       15978 :         computer_val = data_blob_string_const("computer");
    2884       15978 :         val = ldb_msg_find_val(el, &computer_val);
    2885       15978 :         if (val != NULL) {
    2886        1533 :                 is_computer_objectclass = true;
    2887             :         }
    2888             : 
    2889       15978 :         old_ufa = old_uac & UF_ACCOUNT_TYPE_MASK;
    2890       15978 :         old_atype = ds_uf2atype(old_ufa);
    2891       15978 :         old_pgrid = ds_uf2prim_group_rid(old_uac);
    2892             : 
    2893       15978 :         new_ufa = new_uac & UF_ACCOUNT_TYPE_MASK;
    2894       15978 :         if (new_ufa == 0) {
    2895             :                 /*
    2896             :                  * "userAccountControl" = 0 or missing one of the
    2897             :                  * types means "UF_NORMAL_ACCOUNT".  See MS-SAMR
    2898             :                  * 3.1.1.8.10 point 8
    2899             :                  */
    2900         267 :                 new_ufa = UF_NORMAL_ACCOUNT;
    2901         267 :                 new_uac |= new_ufa;
    2902             :         }
    2903       15978 :         sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
    2904       15978 :         if (sid == NULL) {
    2905           0 :                 return ldb_module_operr(ac->module);
    2906             :         }
    2907             : 
    2908       15978 :         ret = samldb_check_user_account_control_rules(ac, sid,
    2909             :                                                       raw_uac,
    2910             :                                                       new_uac,
    2911             :                                                       old_uac,
    2912             :                                                       is_computer_objectclass);
    2913       15978 :         if (ret != LDB_SUCCESS) {
    2914         175 :                 return ret;
    2915             :         }
    2916             : 
    2917       15803 :         new_atype = ds_uf2atype(new_ufa);
    2918       15803 :         new_pgrid = ds_uf2prim_group_rid(new_uac);
    2919             : 
    2920       15803 :         clear_uac = (old_uac | old_uac_computed) & ~raw_uac;
    2921             : 
    2922       15803 :         switch (new_ufa) {
    2923       14458 :         case UF_NORMAL_ACCOUNT:
    2924       14458 :                 new_is_critical = old_is_critical;
    2925       14458 :                 break;
    2926             : 
    2927           0 :         case UF_INTERDOMAIN_TRUST_ACCOUNT:
    2928           0 :                 new_is_critical = true;
    2929           0 :                 break;
    2930             : 
    2931         706 :         case UF_WORKSTATION_TRUST_ACCOUNT:
    2932         706 :                 new_is_critical = false;
    2933         706 :                 if (new_uac & UF_PARTIAL_SECRETS_ACCOUNT) {
    2934         205 :                         new_is_critical = true;
    2935             :                 }
    2936         670 :                 break;
    2937             : 
    2938         602 :         case UF_SERVER_TRUST_ACCOUNT:
    2939         602 :                 new_is_critical = true;
    2940         602 :                 break;
    2941             : 
    2942           0 :         default:
    2943           0 :                 ldb_asprintf_errstring(ldb,
    2944             :                         "%08X: samldb: invalid userAccountControl[0x%08X]",
    2945           0 :                         W_ERROR_V(WERR_INVALID_PARAMETER), raw_uac);
    2946           0 :                 return LDB_ERR_OTHER;
    2947             :         }
    2948             : 
    2949       15803 :         if (old_atype != new_atype) {
    2950         142 :                 ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg,
    2951             :                                             "sAMAccountType", new_atype,
    2952             :                                             LDB_FLAG_MOD_REPLACE);
    2953         142 :                 if (ret != LDB_SUCCESS) {
    2954           0 :                         return ret;
    2955             :                 }
    2956             :         }
    2957             : 
    2958             :         /* As per MS-SAMR 3.1.1.8.10 these flags have not to be set */
    2959       15803 :         if ((clear_uac & UF_LOCKOUT) && (old_lockoutTime != 0)) {
    2960             :                 /* "lockoutTime" reset as per MS-SAMR 3.1.1.8.10 */
    2961          10 :                 ldb_msg_remove_attr(ac->msg, "lockoutTime");
    2962          10 :                 ret = samdb_msg_append_uint64(ldb, ac->msg, ac->msg, "lockoutTime",
    2963             :                                               (NTTIME)0, LDB_FLAG_MOD_REPLACE);
    2964          10 :                 if (ret != LDB_SUCCESS) {
    2965           0 :                         return ret;
    2966             :                 }
    2967             :         }
    2968             : 
    2969             :         /*
    2970             :          * "isCriticalSystemObject" might be set/changed
    2971             :          *
    2972             :          * Even a change from UF_NORMAL_ACCOUNT (implicitly FALSE) to
    2973             :          * UF_WORKSTATION_TRUST_ACCOUNT (actually FALSE) triggers
    2974             :          * creating the attribute.
    2975             :          */
    2976       15803 :         if (old_is_critical != new_is_critical || old_atype != new_atype) {
    2977         221 :                 ret = ldb_msg_append_string(ac->msg, "isCriticalSystemObject",
    2978             :                                             new_is_critical ? "TRUE": "FALSE",
    2979             :                                             LDB_FLAG_MOD_REPLACE);
    2980         221 :                 if (ret != LDB_SUCCESS) {
    2981           0 :                         return ret;
    2982             :                 }
    2983             :         }
    2984             : 
    2985       15803 :         if (!ldb_msg_find_element(ac->msg, "primaryGroupID") &&
    2986             :             (old_pgrid != new_pgrid)) {
    2987             :                 /* Older AD deployments don't know about the RODC group */
    2988         224 :                 if (new_pgrid == DOMAIN_RID_READONLY_DCS) {
    2989          21 :                         ret = samldb_prim_group_tester(ac, new_pgrid);
    2990          21 :                         if (ret != LDB_SUCCESS) {
    2991           0 :                                 return ret;
    2992             :                         }
    2993             :                 }
    2994             : 
    2995         224 :                 ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg,
    2996             :                                             "primaryGroupID", new_pgrid,
    2997             :                                             LDB_FLAG_MOD_REPLACE);
    2998         224 :                 if (ret != LDB_SUCCESS) {
    2999           0 :                         return ret;
    3000             :                 }
    3001             :         }
    3002             : 
    3003             :         /* Propagate eventual "userAccountControl" attribute changes */
    3004       15803 :         if (old_uac != new_uac) {
    3005       15196 :                 char *tempstr = talloc_asprintf(ac->msg, "%d",
    3006             :                                                 new_uac);
    3007       15196 :                 if (tempstr == NULL) {
    3008           0 :                         return ldb_module_oom(ac->module);
    3009             :                 }
    3010             : 
    3011       15196 :                 ret = ldb_msg_add_empty(ac->msg,
    3012             :                                         "userAccountControl",
    3013             :                                         LDB_FLAG_MOD_REPLACE,
    3014             :                                         &el);
    3015       15196 :                 el->values = talloc(ac->msg, struct ldb_val);
    3016       15196 :                 el->num_values = 1;
    3017       15196 :                 el->values[0].data = (uint8_t *) tempstr;
    3018       15196 :                 el->values[0].length = strlen(tempstr);
    3019             :         } else {
    3020         607 :                 ldb_msg_remove_attr(ac->msg, "userAccountControl");
    3021             :         }
    3022             : 
    3023       15694 :         return LDB_SUCCESS;
    3024             : }
    3025             : 
    3026          59 : static int samldb_check_pwd_last_set_acl(struct samldb_ctx *ac,
    3027             :                                          struct dom_sid *sid)
    3028             : {
    3029          59 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    3030          59 :         int ret = 0;
    3031          59 :         struct security_token *user_token = NULL;
    3032          59 :         struct security_descriptor *domain_sd = NULL;
    3033          59 :         struct ldb_dn *domain_dn = ldb_get_default_basedn(ldb_module_get_ctx(ac->module));
    3034          59 :         const char *operation = "";
    3035          59 :         const struct dsdb_class *objectclass = NULL;
    3036             : 
    3037          59 :         if (dsdb_module_am_system(ac->module)) {
    3038           1 :                 return LDB_SUCCESS;
    3039             :         }
    3040             : 
    3041          58 :         switch (ac->req->operation) {
    3042           0 :         case LDB_ADD:
    3043           0 :                 operation = "add";
    3044           0 :                 break;
    3045          58 :         case LDB_MODIFY:
    3046          58 :                 operation = "modify";
    3047          58 :                 break;
    3048           0 :         default:
    3049           0 :                 return ldb_module_operr(ac->module);
    3050             :         }
    3051             : 
    3052          58 :         user_token = acl_user_token(ac->module);
    3053          58 :         if (user_token == NULL) {
    3054           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    3055             :         }
    3056             : 
    3057          58 :         ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass);
    3058          58 :         if (ret != LDB_SUCCESS) {
    3059           0 :                 return ret;
    3060             :         }
    3061          58 :         ret = acl_check_extended_right(ac,
    3062             :                                        ac->module,
    3063             :                                        ac->req,
    3064             :                                        objectclass,
    3065             :                                        domain_sd,
    3066             :                                        user_token,
    3067             :                                        GUID_DRS_UNEXPIRE_PASSWORD,
    3068             :                                        SEC_ADS_CONTROL_ACCESS,
    3069             :                                        sid);
    3070          58 :         if (ret != LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS) {
    3071          58 :                 return ret;
    3072             :         }
    3073             : 
    3074           0 :         ldb_debug_set(ldb, LDB_DEBUG_WARNING,
    3075             :                       "Failed to %s %s: "
    3076             :                       "Setting pwdLastSet to -1 requires the "
    3077             :                       "Unexpire-Password right that was not given "
    3078             :                       "on the Domain object",
    3079             :                       operation,
    3080           0 :                       ldb_dn_get_linearized(ac->msg->dn));
    3081           0 :         dsdb_acl_debug(domain_sd, user_token,
    3082             :                        domain_dn, true, 10);
    3083             : 
    3084           0 :         return ret;
    3085             : }
    3086             : 
    3087             : /**
    3088             :  * This function is called on LDB modify operations. It performs some additions/
    3089             :  * replaces on the current LDB message when "pwdLastSet" changes.
    3090             :  */
    3091         321 : static int samldb_pwd_last_set_change(struct samldb_ctx *ac)
    3092             : {
    3093         321 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    3094         321 :         NTTIME last_set = 0;
    3095         321 :         struct ldb_message_element *el = NULL;
    3096         321 :         struct ldb_message *tmp_msg = NULL;
    3097         321 :         struct dom_sid *self_sid = NULL;
    3098          11 :         int ret;
    3099         321 :         struct ldb_result *res = NULL;
    3100         321 :         const char * const attrs[] = {
    3101             :                 "objectSid",
    3102             :                 NULL
    3103             :         };
    3104             : 
    3105         332 :         ret = dsdb_get_expected_new_values(ac,
    3106         321 :                                            ac->msg,
    3107             :                                            "pwdLastSet",
    3108             :                                            &el,
    3109         321 :                                            ac->req->operation);
    3110         321 :         if (ret != LDB_SUCCESS) {
    3111           0 :                 return ret;
    3112             :         }
    3113             : 
    3114         321 :         if (el == NULL || el->num_values == 0) {
    3115           6 :                 ldb_asprintf_errstring(ldb,
    3116             :                         "%08X: samldb: 'pwdLastSet' can't be deleted!",
    3117           6 :                         W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
    3118           6 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    3119             :         }
    3120             : 
    3121             :         /* Create a temporary message for fetching the "userAccountControl" */
    3122         315 :         tmp_msg = ldb_msg_new(ac->msg);
    3123         315 :         if (tmp_msg == NULL) {
    3124           0 :                 return ldb_module_oom(ac->module);
    3125             :         }
    3126         315 :         ret = ldb_msg_add(tmp_msg, el, 0);
    3127         315 :         if (ret != LDB_SUCCESS) {
    3128           0 :                 return ret;
    3129             :         }
    3130         315 :         last_set = samdb_result_nttime(tmp_msg, "pwdLastSet", 0);
    3131         315 :         talloc_free(tmp_msg);
    3132             : 
    3133             :         /*
    3134             :          * Setting -1 (0xFFFFFFFFFFFFFFFF) requires the Unexpire-Password right
    3135             :          */
    3136         315 :         if (last_set != UINT64_MAX) {
    3137         245 :                 return LDB_SUCCESS;
    3138             :         }
    3139             : 
    3140             :         /* Fetch the "objectSid" */
    3141          59 :         ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
    3142             :                                     DSDB_FLAG_NEXT_MODULE, ac->req);
    3143          59 :         if (ret != LDB_SUCCESS) {
    3144           0 :                 return ret;
    3145             :         }
    3146          59 :         self_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
    3147          59 :         if (self_sid == NULL) {
    3148           0 :                 return ldb_module_operr(ac->module);
    3149             :         }
    3150             : 
    3151          59 :         ret = samldb_check_pwd_last_set_acl(ac, self_sid);
    3152          59 :         if (ret != LDB_SUCCESS) {
    3153           0 :                 return ret;
    3154             :         }
    3155             : 
    3156          59 :         return LDB_SUCCESS;
    3157             : }
    3158             : 
    3159         189 : static int samldb_lockout_time(struct samldb_ctx *ac)
    3160             : {
    3161         189 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    3162           0 :         NTTIME lockoutTime;
    3163           0 :         struct ldb_message_element *el;
    3164           0 :         struct ldb_message *tmp_msg;
    3165           0 :         int ret;
    3166             : 
    3167         189 :         ret = dsdb_get_expected_new_values(ac,
    3168         189 :                                            ac->msg,
    3169             :                                            "lockoutTime",
    3170             :                                            &el,
    3171         189 :                                            ac->req->operation);
    3172         189 :         if (ret != LDB_SUCCESS) {
    3173           0 :                 return ret;
    3174             :         }
    3175             : 
    3176         189 :         if (el == NULL || el->num_values == 0) {
    3177           0 :                 ldb_asprintf_errstring(ldb,
    3178             :                         "%08X: samldb: 'lockoutTime' can't be deleted!",
    3179           0 :                         W_ERROR_V(WERR_DS_ILLEGAL_MOD_OPERATION));
    3180           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    3181             :         }
    3182             : 
    3183             :         /* Create a temporary message for fetching the "lockoutTime" */
    3184         189 :         tmp_msg = ldb_msg_new(ac->msg);
    3185         189 :         if (tmp_msg == NULL) {
    3186           0 :                 return ldb_module_oom(ac->module);
    3187             :         }
    3188         189 :         ret = ldb_msg_add(tmp_msg, el, 0);
    3189         189 :         if (ret != LDB_SUCCESS) {
    3190           0 :                 return ret;
    3191             :         }
    3192         189 :         lockoutTime = ldb_msg_find_attr_as_int64(tmp_msg,
    3193             :                                                  "lockoutTime",
    3194             :                                                  0);
    3195         189 :         talloc_free(tmp_msg);
    3196             : 
    3197         189 :         if (lockoutTime != 0) {
    3198          63 :                 return LDB_SUCCESS;
    3199             :         }
    3200             : 
    3201             :         /* lockoutTime == 0 resets badPwdCount */
    3202         126 :         ldb_msg_remove_attr(ac->msg, "badPwdCount");
    3203         126 :         ret = samdb_msg_append_int(ldb, ac->msg, ac->msg,
    3204             :                                    "badPwdCount", 0,
    3205             :                                    LDB_FLAG_MOD_REPLACE);
    3206         126 :         if (ret != LDB_SUCCESS) {
    3207           0 :                 return ret;
    3208             :         }
    3209             : 
    3210         126 :         return LDB_SUCCESS;
    3211             : }
    3212             : 
    3213         146 : static int samldb_group_type_change(struct samldb_ctx *ac)
    3214             : {
    3215         146 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    3216           0 :         uint32_t group_type, old_group_type, account_type;
    3217           0 :         struct ldb_message_element *el;
    3218           0 :         struct ldb_message *tmp_msg;
    3219           0 :         int ret;
    3220           0 :         struct ldb_result *res;
    3221         146 :         const char * const attrs[] = { "groupType", NULL };
    3222             : 
    3223         146 :         ret = dsdb_get_expected_new_values(ac,
    3224         146 :                                            ac->msg,
    3225             :                                            "groupType",
    3226             :                                            &el,
    3227         146 :                                            ac->req->operation);
    3228         146 :         if (ret != LDB_SUCCESS) {
    3229           0 :                 return ret;
    3230             :         }
    3231             : 
    3232         146 :         if (el == NULL) {
    3233             :                 /* we are not affected */
    3234           3 :                 return LDB_SUCCESS;
    3235             :         }
    3236             : 
    3237             :         /* Create a temporary message for fetching the "groupType" */
    3238         143 :         tmp_msg = ldb_msg_new(ac->msg);
    3239         143 :         if (tmp_msg == NULL) {
    3240           0 :                 return ldb_module_oom(ac->module);
    3241             :         }
    3242         143 :         ret = ldb_msg_add(tmp_msg, el, 0);
    3243         143 :         if (ret != LDB_SUCCESS) {
    3244           0 :                 return ret;
    3245             :         }
    3246         143 :         group_type = ldb_msg_find_attr_as_uint(tmp_msg, "groupType", 0);
    3247         143 :         talloc_free(tmp_msg);
    3248             : 
    3249         143 :         ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, attrs,
    3250             :                                     DSDB_FLAG_NEXT_MODULE |
    3251             :                                     DSDB_SEARCH_SHOW_DELETED, ac->req);
    3252         143 :         if (ret != LDB_SUCCESS) {
    3253           0 :                 return ret;
    3254             :         }
    3255         143 :         old_group_type = ldb_msg_find_attr_as_uint(res->msgs[0], "groupType", 0);
    3256         143 :         if (old_group_type == 0) {
    3257           0 :                 return ldb_operr(ldb);
    3258             :         }
    3259             : 
    3260             :         /* Group type switching isn't so easy as it seems: We can only
    3261             :          * change in this directions: global <-> universal <-> local
    3262             :          * On each step also the group type itself
    3263             :          * (security/distribution) is variable. */
    3264             : 
    3265         143 :         if (ldb_request_get_control(ac->req, LDB_CONTROL_PROVISION_OID) == NULL) {
    3266         143 :                 switch (group_type) {
    3267          41 :                 case GTYPE_SECURITY_GLOBAL_GROUP:
    3268             :                 case GTYPE_DISTRIBUTION_GLOBAL_GROUP:
    3269             :                         /* change to "universal" allowed */
    3270          41 :                         if ((old_group_type == GTYPE_SECURITY_DOMAIN_LOCAL_GROUP) ||
    3271           0 :                         (old_group_type == GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP)) {
    3272           9 :                                 ldb_set_errstring(ldb,
    3273             :                                         "samldb: Change from security/distribution local group forbidden!");
    3274           9 :                                 return LDB_ERR_UNWILLING_TO_PERFORM;
    3275             :                         }
    3276          32 :                 break;
    3277             : 
    3278          43 :                 case GTYPE_SECURITY_UNIVERSAL_GROUP:
    3279             :                 case GTYPE_DISTRIBUTION_UNIVERSAL_GROUP:
    3280             :                         /* each change allowed */
    3281          43 :                 break;
    3282          44 :                 case GTYPE_SECURITY_DOMAIN_LOCAL_GROUP:
    3283             :                 case GTYPE_DISTRIBUTION_DOMAIN_LOCAL_GROUP:
    3284             :                         /* change to "universal" allowed */
    3285          44 :                         if ((old_group_type == GTYPE_SECURITY_GLOBAL_GROUP) ||
    3286           0 :                         (old_group_type == GTYPE_DISTRIBUTION_GLOBAL_GROUP)) {
    3287           9 :                                 ldb_set_errstring(ldb,
    3288             :                                         "samldb: Change from security/distribution global group forbidden!");
    3289           9 :                                 return LDB_ERR_UNWILLING_TO_PERFORM;
    3290             :                         }
    3291          35 :                 break;
    3292             : 
    3293          15 :                 case GTYPE_SECURITY_BUILTIN_LOCAL_GROUP:
    3294             :                 default:
    3295             :                         /* we don't allow this "groupType" values */
    3296          15 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    3297           0 :                 break;
    3298             :                 }
    3299             :         }
    3300             : 
    3301         110 :         account_type =  ds_gtype2atype(group_type);
    3302         110 :         if (account_type == 0) {
    3303           0 :                 ldb_set_errstring(ldb, "samldb: Unrecognized account type!");
    3304           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    3305             :         }
    3306         110 :         ret = samdb_msg_append_uint(ldb, ac->msg, ac->msg, "sAMAccountType",
    3307             :                                     account_type, LDB_FLAG_MOD_REPLACE);
    3308         110 :         if (ret != LDB_SUCCESS) {
    3309           0 :                 return ret;
    3310             :         }
    3311             : 
    3312         110 :         return LDB_SUCCESS;
    3313             : }
    3314             : 
    3315        5159 : static int samldb_member_check(struct samldb_ctx *ac)
    3316             : {
    3317        5159 :         const char * const attrs[] = { "objectSid", NULL };
    3318        5159 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    3319          39 :         struct ldb_message_element *el;
    3320          39 :         struct ldb_dn *member_dn;
    3321          39 :         struct dom_sid *sid;
    3322          39 :         struct ldb_result *res;
    3323          39 :         struct dom_sid *group_sid;
    3324          39 :         unsigned int i, j;
    3325          39 :         int ret;
    3326             : 
    3327             :         /* Fetch information from the existing object */
    3328             : 
    3329        5159 :         ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
    3330             :                                  DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req, NULL);
    3331        5159 :         if (ret != LDB_SUCCESS) {
    3332           0 :                 return ret;
    3333             :         }
    3334        5159 :         if (res->count != 1) {
    3335           0 :                 return ldb_operr(ldb);
    3336             :         }
    3337             : 
    3338        5159 :         group_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
    3339        5159 :         if (group_sid == NULL) {
    3340           0 :                 return ldb_operr(ldb);
    3341             :         }
    3342             : 
    3343             :         /* We've to walk over all modification entries and consider the "member"
    3344             :          * ones. */
    3345       14394 :         for (i = 0; i < ac->msg->num_elements; i++) {
    3346        9238 :                 if (ldb_attr_cmp(ac->msg->elements[i].name, "member") != 0) {
    3347           0 :                         continue;
    3348             :                 }
    3349             : 
    3350        9199 :                 el = &ac->msg->elements[i];
    3351       18810 :                 for (j = 0; j < el->num_values; j++) {
    3352          40 :                         struct ldb_result *group_res;
    3353        9575 :                         const char *group_attrs[] = { "primaryGroupID" , NULL };
    3354          40 :                         uint32_t prim_group_rid;
    3355             : 
    3356        9575 :                         if (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE) {
    3357             :                                 /* Deletes will be handled in
    3358             :                                  * repl_meta_data, and deletes not
    3359             :                                  * matching a member will return
    3360             :                                  * LDB_ERR_UNWILLING_TO_PERFORM
    3361             :                                  * there */
    3362        1026 :                                 continue;
    3363             :                         }
    3364             : 
    3365        8988 :                         member_dn = ldb_dn_from_ldb_val(ac, ldb,
    3366        8979 :                                                         &el->values[j]);
    3367        8979 :                         if (!ldb_dn_validate(member_dn)) {
    3368           3 :                                 return ldb_operr(ldb);
    3369             :                         }
    3370             : 
    3371             :                         /* Denies to add "member"s to groups which are primary
    3372             :                          * ones for them - in this case return
    3373             :                          * ERR_ENTRY_ALREADY_EXISTS. */
    3374             : 
    3375        8979 :                         ret = dsdb_module_search_dn(ac->module, ac, &group_res,
    3376             :                                                     member_dn, group_attrs,
    3377             :                                                     DSDB_FLAG_NEXT_MODULE, ac->req);
    3378        8979 :                         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    3379             :                                 /* member DN doesn't exist yet */
    3380           0 :                                 continue;
    3381             :                         }
    3382        8979 :                         if (ret != LDB_SUCCESS) {
    3383           0 :                                 return ret;
    3384             :                         }
    3385        8979 :                         prim_group_rid = ldb_msg_find_attr_as_uint(group_res->msgs[0], "primaryGroupID", (uint32_t)-1);
    3386        8979 :                         if (prim_group_rid == (uint32_t) -1) {
    3387             :                                 /* the member hasn't to be a user account ->
    3388             :                                  * therefore no check needed in this case. */
    3389         430 :                                 continue;
    3390             :                         }
    3391             : 
    3392        8549 :                         sid = dom_sid_add_rid(ac, samdb_domain_sid(ldb),
    3393             :                                               prim_group_rid);
    3394        8549 :                         if (sid == NULL) {
    3395           0 :                                 return ldb_operr(ldb);
    3396             :                         }
    3397             : 
    3398        8549 :                         if (dom_sid_equal(group_sid, sid)) {
    3399           3 :                                 ldb_asprintf_errstring(ldb,
    3400             :                                                        "samldb: member %s already set via primaryGroupID %u",
    3401             :                                                        ldb_dn_get_linearized(member_dn), prim_group_rid);
    3402           3 :                                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
    3403             :                         }
    3404             :                 }
    3405             :         }
    3406             : 
    3407        5156 :         talloc_free(res);
    3408             : 
    3409        5156 :         return LDB_SUCCESS;
    3410             : }
    3411             : 
    3412             : /* SAM objects have special rules regarding the "description" attribute on
    3413             :  * modify operations. */
    3414        1037 : static int samldb_description_check(struct samldb_ctx *ac, bool *modified)
    3415             : {
    3416        1037 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    3417        1037 :         const char * const attrs[] = { "objectClass", "description", NULL };
    3418         123 :         struct ldb_result *res;
    3419         123 :         unsigned int i;
    3420         123 :         int ret;
    3421             : 
    3422             :         /* Fetch information from the existing object */
    3423        1037 :         ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
    3424             :                                  DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED, ac->req,
    3425             :                                  "(|(objectclass=user)(objectclass=group)(objectclass=samDomain)(objectclass=samServer))");
    3426        1037 :         if (ret != LDB_SUCCESS) {
    3427             :                 /* don't treat it specially ... let normal error codes
    3428             :                    happen from other places */
    3429           0 :                 ldb_reset_err_string(ldb);
    3430           0 :                 return LDB_SUCCESS;
    3431             :         }
    3432        1037 :         if (res->count == 0) {
    3433             :                 /* we didn't match the filter */
    3434         315 :                 talloc_free(res);
    3435         315 :                 return LDB_SUCCESS;
    3436             :         }
    3437             : 
    3438             :         /* We've to walk over all modification entries and consider the
    3439             :          * "description" ones. */
    3440        2536 :         for (i = 0; i < ac->msg->num_elements; i++) {
    3441        1814 :                 if (ldb_attr_cmp(ac->msg->elements[i].name, "description") == 0) {
    3442         725 :                         ac->msg->elements[i].flags |= LDB_FLAG_INTERNAL_FORCE_SINGLE_VALUE_CHECK;
    3443         725 :                         *modified = true;
    3444             :                 }
    3445             :         }
    3446             : 
    3447         722 :         talloc_free(res);
    3448             : 
    3449         722 :         return LDB_SUCCESS;
    3450             : }
    3451             : 
    3452             : #define SPN_ALIAS_NONE 0
    3453             : #define SPN_ALIAS_LINK 1
    3454             : #define SPN_ALIAS_TARGET 2
    3455             : 
    3456        5838 : static int find_spn_aliases(struct ldb_context *ldb,
    3457             :                             TALLOC_CTX *mem_ctx,
    3458             :                             const char *service_class,
    3459             :                             char ***aliases,
    3460             :                             size_t *n_aliases,
    3461             :                             int *direction)
    3462             : {
    3463             :         /*
    3464             :          * If you change the way this works, you should also look at changing
    3465             :          * LDB_lookup_spn_alias() in source4/dsdb/samdb/cracknames.c, which
    3466             :          * does some of the same work.
    3467             :          *
    3468             :          * In particular, note that sPNMappings are resolved on a first come,
    3469             :          * first served basis. For example, if we have
    3470             :          *
    3471             :          *  host=ldap,cifs
    3472             :          *  foo=ldap
    3473             :          *  cifs=host,alerter
    3474             :          *
    3475             :          * then 'ldap', 'cifs', and 'host' will resolve to 'host', and
    3476             :          * 'alerter' will resolve to 'cifs'.
    3477             :          *
    3478             :          * If this resolution method is made more complicated, then the
    3479             :          * cracknames function should also be changed.
    3480             :          */
    3481         272 :         size_t i, j;
    3482         272 :         int ret;
    3483         272 :         bool ok;
    3484        5838 :         struct ldb_result *res = NULL;
    3485        5838 :         struct ldb_message_element *spnmappings = NULL;
    3486        5838 :         TALLOC_CTX *tmp_ctx = NULL;
    3487        5838 :         struct ldb_dn *service_dn = NULL;
    3488             : 
    3489        5838 :         const char *attrs[] = {
    3490             :                 "sPNMappings",
    3491             :                 NULL
    3492             :         };
    3493             : 
    3494        5838 :         *direction = SPN_ALIAS_NONE;
    3495             : 
    3496        5838 :         tmp_ctx = talloc_new(mem_ctx);
    3497        5838 :         if (tmp_ctx == NULL) {
    3498           0 :                 return ldb_oom(ldb);
    3499             :         }
    3500             : 
    3501        5838 :         service_dn = ldb_dn_new(
    3502             :                 tmp_ctx, ldb,
    3503             :                 "CN=Directory Service,CN=Windows NT,CN=Services");
    3504        5838 :         if (service_dn == NULL) {
    3505           0 :                 talloc_free(tmp_ctx);
    3506           0 :                 return ldb_oom(ldb);
    3507             :         }
    3508             : 
    3509        5838 :         ok = ldb_dn_add_base(service_dn, ldb_get_config_basedn(ldb));
    3510        5838 :         if (! ok) {
    3511           0 :                 talloc_free(tmp_ctx);
    3512           0 :                 return LDB_ERR_OPERATIONS_ERROR;
    3513             :         }
    3514             : 
    3515        5838 :         ret = ldb_search(ldb, tmp_ctx, &res, service_dn, LDB_SCOPE_BASE,
    3516             :                          attrs, "(objectClass=nTDSService)");
    3517             : 
    3518        5838 :         if (ret != LDB_SUCCESS || res->count != 1) {
    3519           0 :                 DBG_WARNING("sPNMappings not found.\n");
    3520           0 :                 talloc_free(tmp_ctx);
    3521           0 :                 return ret;
    3522             :         }
    3523             : 
    3524        5838 :         spnmappings = ldb_msg_find_element(res->msgs[0], "sPNMappings");
    3525        5838 :         if (spnmappings == NULL || spnmappings->num_values == 0) {
    3526           0 :                 DBG_WARNING("no sPNMappings attribute\n");
    3527           0 :                 talloc_free(tmp_ctx);
    3528           0 :                 return LDB_ERR_NO_SUCH_OBJECT;
    3529             :         }
    3530        5838 :         *n_aliases = 0;
    3531             : 
    3532        7445 :         for (i = 0; i < spnmappings->num_values; i++) {
    3533        5838 :                 char *p = NULL;
    3534        6110 :                 char *mapping = talloc_strndup(
    3535             :                         tmp_ctx,
    3536        5838 :                         (char *)spnmappings->values[i].data,
    3537        5838 :                         spnmappings->values[i].length);
    3538        5838 :                 if (mapping == NULL) {
    3539           0 :                         talloc_free(tmp_ctx);
    3540           0 :                         return ldb_oom(ldb);
    3541             :                 }
    3542             : 
    3543        5838 :                 p = strchr(mapping, '=');
    3544        5838 :                 if (p == NULL) {
    3545           0 :                         talloc_free(tmp_ctx);
    3546           0 :                         return LDB_ERR_ALIAS_PROBLEM;
    3547             :                 }
    3548        5838 :                 p[0] = '\0';
    3549        5838 :                 p++;
    3550             : 
    3551        5838 :                 if (strcasecmp(mapping, service_class) == 0) {
    3552             :                         /*
    3553             :                          * We need to return the reverse aliases for this one.
    3554             :                          *
    3555             :                          * typically, this means the service_class is "host"
    3556             :                          * and the mapping is "host=alerter,appmgmt,cisvc,..",
    3557             :                          * so we get "alerter", "appmgmt", etc in the list of
    3558             :                          * aliases.
    3559             :                          */
    3560             : 
    3561             :                         /* There is one more field than there are commas */
    3562        3716 :                         size_t n = 1;
    3563             : 
    3564     1560240 :                         for (j = 0; p[j] != '\0'; j++) {
    3565     1556300 :                                 if (p[j] == ',') {
    3566      204880 :                                         n++;
    3567      204880 :                                         p[j] = '\0';
    3568             :                                 }
    3569             :                         }
    3570        3940 :                         *aliases = talloc_array(mem_ctx, char*, n);
    3571        3940 :                         if (*aliases == NULL) {
    3572           0 :                                 talloc_free(tmp_ctx);
    3573           0 :                                 return ldb_oom(ldb);
    3574             :                         }
    3575        3940 :                         *n_aliases = n;
    3576        3940 :                         talloc_steal(mem_ctx, mapping);
    3577      212984 :                         for (j = 0; j < n; j++) {
    3578      208820 :                                 (*aliases)[j] = p;
    3579      208820 :                                 p += strlen(p) + 1;
    3580             :                         }
    3581        3940 :                         talloc_free(tmp_ctx);
    3582        3940 :                         *direction = SPN_ALIAS_LINK;
    3583        3940 :                         return LDB_SUCCESS;
    3584             :                 }
    3585             :                 /*
    3586             :                  * We need to look along the list to see if service_class is
    3587             :                  * there; if so, we return a list of one item (probably "host").
    3588             :                  */
    3589        2460 :                 do {
    3590       96539 :                         char *str = p;
    3591       96539 :                         p = strchr(p, ',');
    3592       96539 :                         if (p != NULL) {
    3593       94932 :                                 p[0] = '\0';
    3594       94932 :                                 p++;
    3595             :                         }
    3596       96539 :                         if (strcasecmp(str, service_class) == 0) {
    3597         291 :                                 *aliases = talloc_array(mem_ctx, char*, 1);
    3598         291 :                                 if (*aliases == NULL) {
    3599           0 :                                         talloc_free(tmp_ctx);
    3600           0 :                                         return ldb_oom(ldb);
    3601             :                                 }
    3602         291 :                                 *n_aliases = 1;
    3603         291 :                                 (*aliases)[0] = mapping;
    3604         291 :                                 talloc_steal(mem_ctx, mapping);
    3605         291 :                                 talloc_free(tmp_ctx);
    3606         291 :                                 *direction = SPN_ALIAS_TARGET;
    3607         291 :                                 return LDB_SUCCESS;
    3608             :                         }
    3609       96248 :                 } while (p != NULL);
    3610             :         }
    3611        1607 :         DBG_INFO("no sPNMappings alias for '%s'\n", service_class);
    3612        1607 :         talloc_free(tmp_ctx);
    3613        1607 :         *aliases = NULL;
    3614        1607 :         *n_aliases = 0;
    3615        1607 :         return LDB_SUCCESS;
    3616             : }
    3617             : 
    3618             : 
    3619      215069 : static int get_spn_dn(struct ldb_context *ldb,
    3620             :                       TALLOC_CTX *tmp_ctx,
    3621             :                       const char *candidate,
    3622             :                       struct ldb_dn **dn)
    3623             : {
    3624       12150 :         int ret;
    3625      215069 :         const char *empty_attrs[] = { NULL };
    3626      215069 :         struct ldb_message *msg = NULL;
    3627      215069 :         struct ldb_dn *base_dn = ldb_get_default_basedn(ldb);
    3628             : 
    3629      215069 :         const char *enc_candidate = NULL;
    3630             : 
    3631      215069 :         *dn = NULL;
    3632             : 
    3633      215069 :         enc_candidate = ldb_binary_encode_string(tmp_ctx, candidate);
    3634      215069 :         if (enc_candidate == NULL) {
    3635           0 :                 return ldb_operr(ldb);
    3636             :         }
    3637             : 
    3638      215069 :         ret = dsdb_search_one(ldb,
    3639             :                               tmp_ctx,
    3640             :                               &msg,
    3641             :                               base_dn,
    3642             :                               LDB_SCOPE_SUBTREE,
    3643             :                               empty_attrs,
    3644             :                               0,
    3645             :                               "(servicePrincipalName=%s)",
    3646             :                               enc_candidate);
    3647      215069 :         if (ret != LDB_SUCCESS) {
    3648      202315 :                 return ret;
    3649             :         }
    3650         608 :         *dn = msg->dn;
    3651         608 :         return LDB_SUCCESS;
    3652             : }
    3653             : 
    3654             : 
    3655          68 : static int check_spn_write_rights(struct ldb_context *ldb,
    3656             :                                   TALLOC_CTX *mem_ctx,
    3657             :                                   const char *spn,
    3658             :                                   struct ldb_dn *dn)
    3659             : {
    3660           2 :         int ret;
    3661          68 :         struct ldb_message *msg = NULL;
    3662          68 :         struct ldb_message_element *del_el = NULL;
    3663          68 :         struct ldb_message_element *add_el = NULL;
    3664          68 :         struct ldb_val val = {
    3665             :                 .data = discard_const_p(uint8_t, spn),
    3666          68 :                 .length = strlen(spn)
    3667             :         };
    3668             : 
    3669          68 :         msg = ldb_msg_new(mem_ctx);
    3670          68 :         if (msg == NULL) {
    3671           0 :                 return ldb_oom(ldb);
    3672             :         }
    3673          68 :         msg->dn = dn;
    3674             : 
    3675          68 :         ret = ldb_msg_add_empty(msg,
    3676             :                                 "servicePrincipalName",
    3677             :                                 LDB_FLAG_MOD_DELETE,
    3678             :                                 &del_el);
    3679          68 :         if (ret != LDB_SUCCESS) {
    3680           0 :                 talloc_free(msg);
    3681           0 :                 return ret;
    3682             :         }
    3683             : 
    3684          68 :         del_el->values = talloc_array(msg->elements, struct ldb_val, 1);
    3685          68 :         if (del_el->values == NULL) {
    3686           0 :                 talloc_free(msg);
    3687           0 :                 return ret;
    3688             :         }
    3689             : 
    3690          68 :         del_el->values[0] = val;
    3691          68 :         del_el->num_values = 1;
    3692             : 
    3693          68 :         ret = ldb_msg_add_empty(msg,
    3694             :                                 "servicePrincipalName",
    3695             :                                 LDB_FLAG_MOD_ADD,
    3696             :                                 &add_el);
    3697          68 :         if (ret != LDB_SUCCESS) {
    3698           0 :                 talloc_free(msg);
    3699           0 :                 return ret;
    3700             :         }
    3701             : 
    3702          68 :         add_el->values = talloc_array(msg->elements, struct ldb_val, 1);
    3703          68 :         if (add_el->values == NULL) {
    3704           0 :                 talloc_free(msg);
    3705           0 :                 return ret;
    3706             :         }
    3707             : 
    3708          68 :         add_el->values[0] = val;
    3709          68 :         add_el->num_values = 1;
    3710             : 
    3711          68 :         ret = ldb_modify(ldb, msg);
    3712          68 :         if (ret == LDB_ERR_NO_SUCH_ATTRIBUTE) {
    3713           0 :                 DBG_ERR("hmm I think we're OK, but not sure\n");
    3714          68 :         } else if (ret != LDB_SUCCESS) {
    3715          14 :                 DBG_ERR("SPN write rights check failed with %d\n", ret);
    3716          14 :                 talloc_free(msg);
    3717          14 :                 return ret;
    3718             :         }
    3719          54 :         talloc_free(msg);
    3720          54 :         return LDB_SUCCESS;
    3721             : }
    3722             : 
    3723             : 
    3724        5838 : static int check_spn_alias_collision(struct ldb_context *ldb,
    3725             :                                      TALLOC_CTX *mem_ctx,
    3726             :                                      const char *spn,
    3727             :                                      struct ldb_dn *target_dn)
    3728             : {
    3729         272 :         int ret;
    3730        5838 :         char *service_class = NULL;
    3731        5838 :         char *spn_tail = NULL;
    3732        5838 :         char *p = NULL;
    3733        5838 :         char **aliases = NULL;
    3734        5838 :         size_t n_aliases = 0;
    3735         272 :         size_t i, len;
    3736        5838 :         TALLOC_CTX *tmp_ctx = NULL;
    3737        5838 :         const char *target_dnstr = ldb_dn_get_linearized(target_dn);
    3738         272 :         int link_direction;
    3739             : 
    3740        5838 :         tmp_ctx = talloc_new(mem_ctx);
    3741        5838 :         if (tmp_ctx == NULL) {
    3742           0 :                 return ldb_oom(ldb);
    3743             :         }
    3744             : 
    3745             :         /*
    3746             :          * "dns/example.com/xxx"  gives
    3747             :          *    service_class = "dns"
    3748             :          *    spn_tail      = "example.com/xxx"
    3749             :          */
    3750        5838 :         p = strchr(spn, '/');
    3751        5838 :         if (p == NULL) {
    3752             :                 /* bad SPN */
    3753           0 :                 talloc_free(tmp_ctx);
    3754           0 :                 return ldb_error(ldb,
    3755             :                                  LDB_ERR_OPERATIONS_ERROR,
    3756             :                                  "malformed servicePrincipalName");
    3757             :         }
    3758        5838 :         len = p - spn;
    3759             : 
    3760        5838 :         service_class = talloc_strndup(tmp_ctx, spn, len);
    3761        5838 :         if (service_class == NULL) {
    3762           0 :                 talloc_free(tmp_ctx);
    3763           0 :                 return ldb_oom(ldb);
    3764             :         }
    3765        5838 :         spn_tail = p + 1;
    3766             : 
    3767        5838 :         ret = find_spn_aliases(ldb,
    3768             :                                tmp_ctx,
    3769             :                                service_class,
    3770             :                                &aliases,
    3771             :                                &n_aliases,
    3772             :                                &link_direction);
    3773        5838 :         if (ret != LDB_SUCCESS) {
    3774           0 :                 talloc_free(tmp_ctx);
    3775           0 :                 return ret;
    3776             :         }
    3777             : 
    3778             :         /*
    3779             :          * we have the list of aliases, and now we need to combined them with
    3780             :          * spn_tail and see if we can find the SPN.
    3781             :          */
    3782      214555 :         for (i = 0; i < n_aliases; i++) {
    3783      208759 :                 struct ldb_dn *colliding_dn = NULL;
    3784      208759 :                 const char *colliding_dnstr = NULL;
    3785             : 
    3786      220635 :                 char *candidate = talloc_asprintf(tmp_ctx,
    3787             :                                                   "%s/%s",
    3788      208759 :                                                   aliases[i],
    3789             :                                                   spn_tail);
    3790      208759 :                 if (candidate == NULL) {
    3791           0 :                         talloc_free(tmp_ctx);
    3792          42 :                         return ldb_oom(ldb);
    3793             :                 }
    3794             : 
    3795      208759 :                 ret = get_spn_dn(ldb, tmp_ctx, candidate, &colliding_dn);
    3796      208759 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    3797      208623 :                         DBG_DEBUG("SPN alias '%s' not found (good)\n",
    3798             :                                   candidate);
    3799      208623 :                         talloc_free(candidate);
    3800      208623 :                         continue;
    3801             :                 }
    3802         136 :                 if (ret != LDB_SUCCESS) {
    3803           0 :                         DBG_ERR("SPN '%s' search error %d\n", candidate, ret);
    3804           0 :                         talloc_free(tmp_ctx);
    3805           0 :                         return ret;
    3806             :                 }
    3807             : 
    3808         136 :                 target_dnstr = ldb_dn_get_linearized(target_dn);
    3809             :                 /*
    3810             :                  * We have found an existing SPN that matches the alias. That
    3811             :                  * is OK only if it is on the object we are trying to add to,
    3812             :                  * or if the SPN on the other side is a more generic alias for
    3813             :                  * this one and we also have rights to modify it.
    3814             :                  *
    3815             :                  * That is, we can put "host/X" and "cifs/X" on the same
    3816             :                  * object, but not on different objects, unless we put the
    3817             :                  * host/X on first, and could also change that object when we
    3818             :                  * add cifs/X. It is forbidden to add the objects in the other
    3819             :                  * order.
    3820             :                  *
    3821             :                  * The rationale for this is that adding "cifs/X" effectively
    3822             :                  * changes "host/X" by diverting traffic. If "host/X" can be
    3823             :                  * added after "cifs/X", a sneaky person could get "cifs/X" in
    3824             :                  * first, making "host/X" have less effect than intended.
    3825             :                  *
    3826             :                  * Note: we also can't have "host/X" and "Host/X" on the same
    3827             :                  * object, but that is not relevant here.
    3828             :                  */
    3829             : 
    3830         136 :                 ret = ldb_dn_compare(colliding_dn, target_dn);
    3831         136 :                 if (ret != 0) {
    3832          96 :                         colliding_dnstr = ldb_dn_get_linearized(colliding_dn);
    3833          96 :                         DBG_ERR("trying to add SPN '%s' on '%s' when '%s' is "
    3834             :                                 "on '%s'\n",
    3835             :                                 spn,
    3836             :                                 target_dnstr,
    3837             :                                 candidate,
    3838             :                                 colliding_dnstr);
    3839             : 
    3840          96 :                         if (link_direction == SPN_ALIAS_LINK) {
    3841             :                                 /* we don't allow host/X if there is a
    3842             :                                  * cifs/X */
    3843          28 :                                 talloc_free(tmp_ctx);
    3844          28 :                                 return LDB_ERR_CONSTRAINT_VIOLATION;
    3845             :                         }
    3846          68 :                         ret = check_spn_write_rights(ldb,
    3847             :                                                      tmp_ctx,
    3848             :                                                      candidate,
    3849             :                                                      colliding_dn);
    3850          68 :                         if (ret != LDB_SUCCESS) {
    3851          14 :                                 DBG_ERR("SPN '%s' is on '%s' so '%s' can't be "
    3852             :                                         "added to '%s'\n",
    3853             :                                         candidate,
    3854             :                                         colliding_dnstr,
    3855             :                                         spn,
    3856             :                                         target_dnstr);
    3857          14 :                                 talloc_free(tmp_ctx);
    3858          14 :                                 ldb_asprintf_errstring(ldb,
    3859             :                                                        "samldb: spn[%s] would cause a conflict",
    3860             :                                                        spn);
    3861          14 :                                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    3862             :                         }
    3863             :                 } else {
    3864          40 :                         DBG_INFO("SPNs '%s' and '%s' alias both on '%s'\n",
    3865             :                                  candidate, spn, target_dnstr);
    3866             :                 }
    3867          94 :                 talloc_free(candidate);
    3868             :         }
    3869             : 
    3870        5796 :         talloc_free(tmp_ctx);
    3871        5796 :         return LDB_SUCCESS;
    3872             : }
    3873             : 
    3874        6310 : static int check_spn_direct_collision(struct ldb_context *ldb,
    3875             :                                       TALLOC_CTX *mem_ctx,
    3876             :                                       const char *spn,
    3877             :                                       struct ldb_dn *target_dn)
    3878             : {
    3879         274 :         int ret;
    3880        6310 :         TALLOC_CTX *tmp_ctx = NULL;
    3881        6310 :         struct ldb_dn *colliding_dn = NULL;
    3882        6310 :         const char *target_dnstr = NULL;
    3883        6310 :         const char *colliding_dnstr = NULL;
    3884             : 
    3885        6310 :         tmp_ctx = talloc_new(mem_ctx);
    3886        6310 :         if (tmp_ctx == NULL) {
    3887           0 :                 return ldb_oom(ldb);
    3888             :         }
    3889             : 
    3890        6310 :         ret = get_spn_dn(ldb, tmp_ctx, spn, &colliding_dn);
    3891        6310 :         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    3892        5838 :                 DBG_DEBUG("SPN '%s' not found (good)\n", spn);
    3893        5838 :                 talloc_free(tmp_ctx);
    3894        5838 :                 return LDB_SUCCESS;
    3895             :         }
    3896         472 :         if (ret != LDB_SUCCESS) {
    3897           0 :                 DBG_ERR("SPN '%s' search error %d\n", spn, ret);
    3898           0 :                 talloc_free(tmp_ctx);
    3899           0 :                 if (ret == LDB_ERR_COMPARE_TRUE) {
    3900             :                         /*
    3901             :                          * COMPARE_TRUE has special meaning here and we don't
    3902             :                          * want to return it by mistake.
    3903             :                          */
    3904           0 :                         ret = LDB_ERR_OPERATIONS_ERROR;
    3905             :                 }
    3906           0 :                 return ret;
    3907             :         }
    3908             :         /*
    3909             :          * We have found this exact SPN. This is mostly harmless (depend on
    3910             :          * ADD vs REPLACE) when the spn is being put on the object that
    3911             :          * already has, so we let it through to succeed or fail as some other
    3912             :          * module sees fit.
    3913             :          */
    3914         472 :         target_dnstr = ldb_dn_get_linearized(target_dn);
    3915         472 :         ret = ldb_dn_compare(colliding_dn, target_dn);
    3916         472 :         if (ret != 0) {
    3917          23 :                 colliding_dnstr = ldb_dn_get_linearized(colliding_dn);
    3918          23 :                 DBG_ERR("SPN '%s' is on '%s' so it can't be "
    3919             :                         "added to '%s'\n",
    3920             :                         spn,
    3921             :                         colliding_dnstr,
    3922             :                         target_dnstr);
    3923          23 :                 ldb_asprintf_errstring(ldb,
    3924             :                                        "samldb: spn[%s] would cause a conflict",
    3925             :                                        spn);
    3926          23 :                 talloc_free(tmp_ctx);
    3927          23 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
    3928             :         }
    3929             : 
    3930         449 :         DBG_INFO("SPN '%s' is already on '%s'\n",
    3931             :                  spn, target_dnstr);
    3932         449 :         talloc_free(tmp_ctx);
    3933         449 :         return LDB_ERR_COMPARE_TRUE;
    3934             : }
    3935             : 
    3936             : 
    3937        6326 : static int count_spn_components(struct ldb_val val)
    3938             : {
    3939             :         /*
    3940             :          * a 3 part servicePrincipalName has two slashes, like
    3941             :          * ldap/example.com/DomainDNSZones.example.com.
    3942             :          *
    3943             :          * In krb5_parse_name_flags() we don't count "\/" as a slash (i.e.
    3944             :          * escaped by a backslash), but this is not the behaviour of Windows
    3945             :          * on setting a servicePrincipalName -- slashes are counted regardless
    3946             :          * of backslashes.
    3947             :          *
    3948             :          * Accordingly, here we ignore backslashes. This will reject
    3949             :          * multi-slash SPNs that krb5_parse_name_flags() would accept, and
    3950             :          * allow ones in the form "a\/b" that it won't parse.
    3951             :          */
    3952         274 :         size_t i;
    3953        6326 :         int slashes = 0;
    3954      209725 :         for (i = 0; i < val.length; i++) {
    3955      203407 :                 char c = val.data[i];
    3956      203407 :                 if (c == '/') {
    3957        7691 :                         slashes++;
    3958        7691 :                         if (slashes == 3) {
    3959             :                                 /* at this point we don't care */
    3960           8 :                                 return 4;
    3961             :                         }
    3962             :                 }
    3963             :         }
    3964        6318 :         return slashes + 1;
    3965             : }
    3966             : 
    3967             : 
    3968             : /* Check that "servicePrincipalName" changes do not introduce a collision
    3969             :  * globally. */
    3970        3823 : static int samldb_spn_uniqueness_check(struct samldb_ctx *ac,
    3971             :                                        struct ldb_message_element *spn_el)
    3972             : {
    3973        3823 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    3974         130 :         int ret;
    3975        3823 :         const char *spn = NULL;
    3976         130 :         size_t i;
    3977        3823 :         TALLOC_CTX *tmp_ctx = talloc_new(ac->msg);
    3978        3823 :         if (tmp_ctx == NULL) {
    3979           0 :                 return ldb_oom(ldb);
    3980             :         }
    3981             : 
    3982       10068 :         for (i = 0; i < spn_el->num_values; i++) {
    3983         274 :                 int n_components;
    3984        6326 :                 spn = (char *)spn_el->values[i].data;
    3985             : 
    3986        6326 :                 n_components = count_spn_components(spn_el->values[i]);
    3987        6326 :                 if (n_components > 3 || n_components < 2) {
    3988          16 :                         ldb_asprintf_errstring(ldb,
    3989             :                                                "samldb: spn[%s] invalid with %u components",
    3990             :                                                spn, n_components);
    3991          16 :                         talloc_free(tmp_ctx);
    3992          16 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
    3993             :                 }
    3994             : 
    3995        6584 :                 ret = check_spn_direct_collision(ldb,
    3996             :                                                  tmp_ctx,
    3997             :                                                  spn,
    3998        6310 :                                                  ac->msg->dn);
    3999        6310 :                 if (ret == LDB_ERR_COMPARE_TRUE) {
    4000         449 :                         DBG_INFO("SPN %s re-added to the same object\n", spn);
    4001         449 :                         continue;
    4002             :                 }
    4003        5861 :                 if (ret != LDB_SUCCESS) {
    4004          23 :                         DBG_ERR("SPN %s failed direct uniqueness check\n", spn);
    4005          23 :                         talloc_free(tmp_ctx);
    4006          23 :                         return ret;
    4007             :                 }
    4008             : 
    4009        6110 :                 ret = check_spn_alias_collision(ldb,
    4010             :                                                 tmp_ctx,
    4011             :                                                 spn,
    4012        5838 :                                                 ac->msg->dn);
    4013             : 
    4014        5838 :                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    4015             :                         /* we have no sPNMappings, hence no aliases */
    4016           0 :                         break;
    4017             :                 }
    4018        5838 :                 if (ret != LDB_SUCCESS) {
    4019          42 :                         DBG_ERR("SPN %s failed alias uniqueness check\n", spn);
    4020          42 :                         talloc_free(tmp_ctx);
    4021          42 :                         return ret;
    4022             :                 }
    4023        5796 :                 DBG_INFO("SPN %s seems to be unique\n", spn);
    4024             :         }
    4025             : 
    4026        3742 :         talloc_free(tmp_ctx);
    4027        3742 :         return LDB_SUCCESS;
    4028             : }
    4029             : 
    4030             : 
    4031             : 
    4032             : /* This trigger adapts the "servicePrincipalName" attributes if the
    4033             :  * "dNSHostName" and/or "sAMAccountName" attribute change(s) */
    4034        1611 : static int samldb_service_principal_names_change(struct samldb_ctx *ac)
    4035             : {
    4036        1611 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    4037        1611 :         struct ldb_message_element *el = NULL, *el2 = NULL;
    4038          84 :         struct ldb_message *msg;
    4039        1611 :         const char * const attrs[] = { "servicePrincipalName", NULL };
    4040          84 :         struct ldb_result *res;
    4041        1611 :         const char *dns_hostname = NULL, *old_dns_hostname = NULL,
    4042        1611 :                    *sam_accountname = NULL, *old_sam_accountname = NULL;
    4043          84 :         unsigned int i, j;
    4044          84 :         int ret;
    4045             : 
    4046        1695 :         ret = dsdb_get_expected_new_values(ac,
    4047        1611 :                                            ac->msg,
    4048             :                                            "dNSHostName",
    4049             :                                            &el,
    4050        1611 :                                            ac->req->operation);
    4051        1611 :         if (ret != LDB_SUCCESS) {
    4052           0 :                 return ret;
    4053             :         }
    4054        1695 :         ret = dsdb_get_expected_new_values(ac,
    4055        1611 :                                            ac->msg,
    4056             :                                            "sAMAccountName",
    4057             :                                            &el2,
    4058        1611 :                                            ac->req->operation);
    4059        1611 :         if (ret != LDB_SUCCESS) {
    4060           0 :                 return ret;
    4061             :         }
    4062        1611 :         if ((el == NULL) && (el2 == NULL)) {
    4063             :                 /* we are not affected */
    4064           3 :                 return LDB_SUCCESS;
    4065             :         }
    4066             : 
    4067             :         /* Create a temporary message for fetching the "dNSHostName" */
    4068        1608 :         if (el != NULL) {
    4069         764 :                 const char *dns_attrs[] = { "dNSHostName", NULL };
    4070         764 :                 msg = ldb_msg_new(ac->msg);
    4071         764 :                 if (msg == NULL) {
    4072           0 :                         return ldb_module_oom(ac->module);
    4073             :                 }
    4074         764 :                 ret = ldb_msg_add(msg, el, 0);
    4075         764 :                 if (ret != LDB_SUCCESS) {
    4076           0 :                         return ret;
    4077             :                 }
    4078         764 :                 dns_hostname = talloc_strdup(ac,
    4079             :                                              ldb_msg_find_attr_as_string(msg, "dNSHostName", NULL));
    4080         764 :                 if (dns_hostname == NULL) {
    4081           0 :                         return ldb_module_oom(ac->module);
    4082             :                 }
    4083             : 
    4084         764 :                 talloc_free(msg);
    4085             : 
    4086         764 :                 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn,
    4087             :                                             dns_attrs, DSDB_FLAG_NEXT_MODULE, ac->req);
    4088         764 :                 if (ret == LDB_SUCCESS) {
    4089         764 :                         old_dns_hostname = ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
    4090             :                 }
    4091             :         }
    4092             : 
    4093             :         /* Create a temporary message for fetching the "sAMAccountName" */
    4094        1608 :         if (el2 != NULL) {
    4095         866 :                 char *tempstr, *tempstr2 = NULL;
    4096         866 :                 const char *acct_attrs[] = { "sAMAccountName", NULL };
    4097             : 
    4098         866 :                 msg = ldb_msg_new(ac->msg);
    4099         866 :                 if (msg == NULL) {
    4100           0 :                         return ldb_module_oom(ac->module);
    4101             :                 }
    4102         866 :                 ret = ldb_msg_add(msg, el2, 0);
    4103         866 :                 if (ret != LDB_SUCCESS) {
    4104           0 :                         return ret;
    4105             :                 }
    4106         866 :                 tempstr = talloc_strdup(ac,
    4107             :                                         ldb_msg_find_attr_as_string(msg, "sAMAccountName", NULL));
    4108         866 :                 talloc_free(msg);
    4109             : 
    4110         866 :                 ret = dsdb_module_search_dn(ac->module, ac, &res, ac->msg->dn, acct_attrs,
    4111             :                                             DSDB_FLAG_NEXT_MODULE, ac->req);
    4112         866 :                 if (ret == LDB_SUCCESS) {
    4113         866 :                         tempstr2 = talloc_strdup(ac,
    4114         866 :                                                  ldb_msg_find_attr_as_string(res->msgs[0],
    4115             :                                                                              "sAMAccountName", NULL));
    4116             :                 }
    4117             : 
    4118             : 
    4119             :                 /* The "sAMAccountName" needs some additional trimming: we need
    4120             :                  * to remove the trailing "$"s if they exist. */
    4121         866 :                 if ((tempstr != NULL) && (tempstr[0] != '\0') &&
    4122         866 :                     (tempstr[strlen(tempstr) - 1] == '$')) {
    4123         184 :                         tempstr[strlen(tempstr) - 1] = '\0';
    4124             :                 }
    4125         866 :                 if ((tempstr2 != NULL) && (tempstr2[0] != '\0') &&
    4126         866 :                     (tempstr2[strlen(tempstr2) - 1] == '$')) {
    4127         231 :                         tempstr2[strlen(tempstr2) - 1] = '\0';
    4128             :                 }
    4129         866 :                 sam_accountname = tempstr;
    4130         866 :                 old_sam_accountname = tempstr2;
    4131             :         }
    4132             : 
    4133        1608 :         if (old_dns_hostname == NULL) {
    4134             :                 /* we cannot change when the old name is unknown */
    4135        1492 :                 dns_hostname = NULL;
    4136             :         }
    4137        1724 :         if ((old_dns_hostname != NULL) && (dns_hostname != NULL) &&
    4138         116 :             (strcasecmp_m(old_dns_hostname, dns_hostname) == 0)) {
    4139             :                 /* The "dNSHostName" didn't change */
    4140          51 :                 dns_hostname = NULL;
    4141             :         }
    4142             : 
    4143        1608 :         if (old_sam_accountname == NULL) {
    4144             :                 /* we cannot change when the old name is unknown */
    4145         742 :                 sam_accountname = NULL;
    4146             :         }
    4147        2474 :         if ((old_sam_accountname != NULL) && (sam_accountname != NULL) &&
    4148         866 :             (strcasecmp_m(old_sam_accountname, sam_accountname) == 0)) {
    4149             :                 /* The "sAMAccountName" didn't change */
    4150         443 :                 sam_accountname = NULL;
    4151             :         }
    4152             : 
    4153        1608 :         if ((dns_hostname == NULL) && (sam_accountname == NULL)) {
    4154             :                 /* Well, there are information missing (old name(s)) or the
    4155             :                  * names didn't change. We've nothing to do and can exit here */
    4156        1050 :                 return LDB_SUCCESS;
    4157             :         }
    4158             : 
    4159             :         /*
    4160             :          * Potential "servicePrincipalName" changes in the same request have
    4161             :          * to be handled before the update (Windows behaviour).
    4162             :          *
    4163             :          * We extract the SPN changes into a new message and run it through
    4164             :          * the stack from this module, so that it subjects them to the SPN
    4165             :          * checks we have here.
    4166             :          */
    4167         480 :         el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
    4168         480 :         if (el != NULL) {
    4169          34 :                 msg = ldb_msg_new(ac->msg);
    4170          34 :                 if (msg == NULL) {
    4171           0 :                         return ldb_module_oom(ac->module);
    4172             :                 }
    4173          34 :                 msg->dn = ac->msg->dn;
    4174             : 
    4175           0 :                 do {
    4176          34 :                         ret = ldb_msg_add(msg, el, el->flags);
    4177          34 :                         if (ret != LDB_SUCCESS) {
    4178           0 :                                 return ret;
    4179             :                         }
    4180             : 
    4181          34 :                         ldb_msg_remove_element(ac->msg, el);
    4182             : 
    4183          34 :                         el = ldb_msg_find_element(ac->msg,
    4184             :                                                   "servicePrincipalName");
    4185          34 :                 } while (el != NULL);
    4186             : 
    4187          34 :                 ret = dsdb_module_modify(ac->module, msg,
    4188             :                                          DSDB_FLAG_OWN_MODULE, ac->req);
    4189          34 :                 if (ret != LDB_SUCCESS) {
    4190           0 :                         return ret;
    4191             :                 }
    4192          34 :                 talloc_free(msg);
    4193             :         }
    4194             : 
    4195             :         /* Fetch the "servicePrincipalName"s if any */
    4196         480 :         ret = dsdb_module_search(ac->module, ac, &res, ac->msg->dn, LDB_SCOPE_BASE, attrs,
    4197             :                                  DSDB_FLAG_NEXT_MODULE, ac->req, NULL);
    4198         480 :         if (ret != LDB_SUCCESS) {
    4199           0 :                 return ret;
    4200             :         }
    4201         480 :         if ((res->count != 1) || (res->msgs[0]->num_elements > 1)) {
    4202           0 :                 return ldb_operr(ldb);
    4203             :         }
    4204             : 
    4205         480 :         if (res->msgs[0]->num_elements == 1) {
    4206             :                 /*
    4207             :                  * Yes, we do have "servicePrincipalName"s. First we update them
    4208             :                  * locally, that means we do always substitute the current
    4209             :                  * "dNSHostName" with the new one and/or "sAMAccountName"
    4210             :                  * without "$" with the new one and then we append the
    4211             :                  * modified "servicePrincipalName"s as a message element
    4212             :                  * replace to the modification request (Windows behaviour). We
    4213             :                  * need also to make sure that the values remain case-
    4214             :                  * insensitively unique.
    4215             :                  */
    4216             : 
    4217          71 :                 ret = ldb_msg_add_empty(ac->msg, "servicePrincipalName",
    4218             :                                         LDB_FLAG_MOD_REPLACE, &el);
    4219          71 :                 if (ret != LDB_SUCCESS) {
    4220           0 :                         return ret;
    4221             :                 }
    4222             : 
    4223         199 :                 for (i = 0; i < res->msgs[0]->elements[0].num_values; i++) {
    4224           6 :                         char *old_str, *new_str;
    4225         128 :                         char *pos = NULL;
    4226           6 :                         const char *tok;
    4227           6 :                         struct ldb_val *vals;
    4228         128 :                         bool found = false;
    4229             : 
    4230         128 :                         old_str = (char *)
    4231         128 :                                 res->msgs[0]->elements[0].values[i].data;
    4232             : 
    4233         128 :                         new_str = talloc_strdup(ac->msg,
    4234         128 :                                                 strtok_r(old_str, "/", &pos));
    4235         128 :                         if (new_str == NULL) {
    4236           0 :                                 return ldb_module_oom(ac->module);
    4237             :                         }
    4238             : 
    4239         262 :                         while ((tok = strtok_r(NULL, "/", &pos)) != NULL) {
    4240         247 :                                 if ((dns_hostname != NULL) &&
    4241         113 :                                     (strcasecmp_m(tok, old_dns_hostname) == 0)) {
    4242          57 :                                         tok = dns_hostname;
    4243             :                                 }
    4244         175 :                                 if ((sam_accountname != NULL) &&
    4245          41 :                                     (strcasecmp_m(tok, old_sam_accountname) == 0)) {
    4246          17 :                                         tok = sam_accountname;
    4247             :                                 }
    4248             : 
    4249         134 :                                 new_str = talloc_asprintf(ac->msg, "%s/%s",
    4250             :                                                           new_str, tok);
    4251         134 :                                 if (new_str == NULL) {
    4252           0 :                                         return ldb_module_oom(ac->module);
    4253             :                                 }
    4254             :                         }
    4255             : 
    4256             :                         /* Uniqueness check */
    4257         208 :                         for (j = 0; (!found) && (j < el->num_values); j++) {
    4258          80 :                                 if (strcasecmp_m((char *)el->values[j].data,
    4259             :                                                new_str) == 0) {
    4260          19 :                                         found = true;
    4261             :                                 }
    4262             :                         }
    4263         128 :                         if (found) {
    4264          19 :                                 continue;
    4265             :                         }
    4266             : 
    4267             :                         /*
    4268             :                          * append the new "servicePrincipalName" -
    4269             :                          * code derived from ldb_msg_add_value().
    4270             :                          *
    4271             :                          * Open coded to make it clear that we must
    4272             :                          * append to the MOD_REPLACE el created above.
    4273             :                          */
    4274         109 :                         vals = talloc_realloc(ac->msg, el->values,
    4275             :                                               struct ldb_val,
    4276             :                                               el->num_values + 1);
    4277         109 :                         if (vals == NULL) {
    4278           0 :                                 return ldb_module_oom(ac->module);
    4279             :                         }
    4280         109 :                         el->values = vals;
    4281         109 :                         el->values[el->num_values] = data_blob_string_const(new_str);
    4282         109 :                         ++(el->num_values);
    4283             :                 }
    4284             :         }
    4285             : 
    4286         480 :         talloc_free(res);
    4287             : 
    4288         480 :         return LDB_SUCCESS;
    4289             : }
    4290             : 
    4291             : /* This checks the "fSMORoleOwner" attributes */
    4292        1287 : static int samldb_fsmo_role_owner_check(struct samldb_ctx *ac)
    4293             : {
    4294        1287 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    4295        1287 :         const char * const no_attrs[] = { NULL };
    4296         166 :         struct ldb_message_element *el;
    4297         166 :         struct ldb_message *tmp_msg;
    4298         166 :         struct ldb_dn *res_dn;
    4299         166 :         struct ldb_result *res;
    4300         166 :         int ret;
    4301        1453 :         ret = dsdb_get_expected_new_values(ac,
    4302        1287 :                                            ac->msg,
    4303             :                                            "fSMORoleOwner",
    4304             :                                            &el,
    4305        1287 :                                            ac->req->operation);
    4306        1287 :         if (ret != LDB_SUCCESS) {
    4307           0 :                 return ret;
    4308             :         }
    4309             : 
    4310        1287 :         if (el == NULL) {
    4311             :                 /* we are not affected */
    4312           3 :                 return LDB_SUCCESS;
    4313             :         }
    4314        1284 :         if (el->num_values != 1) {
    4315           6 :                 goto choose_error_code;
    4316             :         }
    4317             : 
    4318             :         /* Create a temporary message for fetching the "fSMORoleOwner" */
    4319        1278 :         tmp_msg = ldb_msg_new(ac->msg);
    4320        1278 :         if (tmp_msg == NULL) {
    4321           0 :                 return ldb_module_oom(ac->module);
    4322             :         }
    4323        1278 :         ret = ldb_msg_add(tmp_msg, el, 0);
    4324        1278 :         if (ret != LDB_SUCCESS) {
    4325           0 :                 return ret;
    4326             :         }
    4327        1278 :         res_dn = ldb_msg_find_attr_as_dn(ldb, ac, tmp_msg, "fSMORoleOwner");
    4328        1278 :         talloc_free(tmp_msg);
    4329             : 
    4330        1278 :         if (res_dn == NULL) {
    4331           0 :                 ldb_set_errstring(ldb,
    4332             :                                   "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
    4333           0 :                 goto choose_error_code;
    4334             :         }
    4335             : 
    4336             :         /* Fetched DN has to reference a "nTDSDSA" entry */
    4337        1278 :         ret = dsdb_module_search(ac->module, ac, &res, res_dn, LDB_SCOPE_BASE,
    4338             :                                  no_attrs,
    4339             :                                  DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
    4340             :                                  ac->req, "(objectClass=nTDSDSA)");
    4341        1278 :         if (ret != LDB_SUCCESS) {
    4342           0 :                 return ret;
    4343             :         }
    4344        1278 :         if (res->count != 1) {
    4345           6 :                 ldb_set_errstring(ldb,
    4346             :                                   "samldb: 'fSMORoleOwner' attributes have to reference 'nTDSDSA' entries!");
    4347           6 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    4348             :         }
    4349             : 
    4350        1272 :         talloc_free(res);
    4351             : 
    4352        1272 :         return LDB_SUCCESS;
    4353             : 
    4354           6 : choose_error_code:
    4355             :         /* this is just how it is */
    4356           6 :         if (ac->req->operation == LDB_ADD) {
    4357           3 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
    4358             :         } else {
    4359           3 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    4360             :         }
    4361             : }
    4362             : 
    4363             : /*
    4364             :  * Return zero if the number of zero bits in the address (looking from low to
    4365             :  * high) is equal to or greater than the length minus the mask. Otherwise it
    4366             :  * returns -1.
    4367             :  */
    4368         140 : static int check_cidr_zero_bits(uint8_t *address, unsigned int len,
    4369             :                                 unsigned int mask)
    4370             : {
    4371             :         /* <address> is an integer in big-endian form, <len> bits long. All
    4372             :            bits between <mask> and <len> must be zero. */
    4373           0 :         int i;
    4374           0 :         unsigned int byte_len;
    4375           0 :         unsigned int byte_mask;
    4376           0 :         unsigned int bit_mask;
    4377         140 :         if (len == 32) {
    4378          60 :                 DBG_INFO("Looking at address %02x%02x%02x%02x, mask %u\n",
    4379             :                          address[0], address[1], address[2], address[3],
    4380             :                           mask);
    4381          80 :         } else if (len == 128){
    4382          80 :                 DBG_INFO("Looking at address "
    4383             :                          "%02x%02x-%02x%02x-%02x%02x-%02x%02x-"
    4384             :                          "%02x%02x-%02x%02x-%02x%02x-%02x%02x, mask %u\n",
    4385             :                          address[0], address[1], address[2], address[3],
    4386             :                          address[4], address[5], address[6], address[7],
    4387             :                          address[8], address[9], address[10], address[11],
    4388             :                          address[12], address[13], address[14], address[15],
    4389             :                          mask);
    4390             :         }
    4391             : 
    4392         140 :         if (mask > len){
    4393           5 :                 DBG_INFO("mask %u is too big (> %u)\n", mask, len);
    4394           5 :                 return -1;
    4395             :         }
    4396         135 :         if (mask == len){
    4397             :                 /* single address subnet.
    4398             :                  * In IPv4 all 255s is invalid by the bitmask != address rule
    4399             :                  * in MS-ADTS. IPv6 does not suffer.
    4400             :                  */
    4401          10 :                 if (len == 32){
    4402           5 :                         if (address[0] == 255 &&
    4403           1 :                             address[1] == 255 &&
    4404           1 :                             address[2] == 255 &&
    4405           1 :                             address[3] == 255){
    4406           1 :                                 return -1;
    4407             :                         }
    4408             :                 }
    4409           9 :                 return 0;
    4410             :         }
    4411             : 
    4412         125 :         byte_len = len / 8;
    4413         125 :         byte_mask = mask / 8;
    4414             : 
    4415         717 :         for (i = byte_len - 1; i > byte_mask; i--){
    4416         594 :                 DBG_DEBUG("checking byte %d %02x\n", i, address[i]);
    4417         594 :                 if (address[i] != 0){
    4418           2 :                         return -1;
    4419             :                 }
    4420             :         }
    4421         123 :         bit_mask = (1 << (8 - (mask & 7))) - 1;
    4422         123 :         DBG_DEBUG("checking bitmask %02x & %02x overlap %02x\n", bit_mask, address[byte_mask],
    4423             :                   bit_mask & address[byte_mask]);
    4424         123 :         if (address[byte_mask] & bit_mask){
    4425          15 :                 return -1;
    4426             :         }
    4427             : 
    4428             :         /* According to MS-ADTS, the mask can't exactly equal the bitmask for
    4429             :          * IPv4 (but this is fine for v6). That is 255.255.80.0/17 is bad,
    4430             :          * because the bitmask implied by "/17" is 255.255.80.0.
    4431             :          *
    4432             :          * The bit_mask used in the previous check is the complement of what
    4433             :          * we want here.
    4434             :          */
    4435         108 :         if (len == 32 && address[byte_mask] == (uint8_t)~bit_mask){
    4436          37 :                 bool ok = false;
    4437          41 :                 for (i = 0; i < byte_mask; i++){
    4438          37 :                         if (address[i] != 255){
    4439          33 :                                 ok = true;
    4440          33 :                                 break;
    4441             :                         }
    4442             :                 }
    4443          37 :                 if (ok == false){
    4444           4 :                         return -1;
    4445             :                 }
    4446             :         }
    4447         104 :         return 0;
    4448             : }
    4449             : 
    4450             : 
    4451             : 
    4452         165 : static int check_address_roundtrip(const char *address, int family,
    4453             :                                    const uint8_t *address_bytes,
    4454             :                                    char *buffer, int buffer_len)
    4455             : {
    4456             :         /*
    4457             :          * Check that the address is in the canonical RFC5952 format for IPv6,
    4458             :          * and lacks extra leading zeros for each dotted decimal for IPv4.
    4459             :          * Handily this is what inet_ntop() gives you.
    4460             :          */
    4461         165 :         const char *address_redux = inet_ntop(family, address_bytes,
    4462             :                                               buffer, buffer_len);
    4463         165 :         if (address_redux == NULL){
    4464           0 :                 DBG_INFO("Address round trip %s failed unexpectedly"
    4465             :                          " with errno %d\n", address, errno);
    4466           0 :                 return -1;
    4467             :         }
    4468         165 :         if (strcasecmp(address, address_redux) != 0){
    4469          25 :                 DBG_INFO("Address %s round trips to %s; fail!\n",
    4470             :                          address, address_redux);
    4471             :                 /* If the address family is IPv6, and the address is in a
    4472             :                    certain range
    4473             : 
    4474             :                  */
    4475          25 :                 if (strchr(address_redux, '.') != NULL){
    4476           7 :                         DEBUG(0, ("The IPv6 address '%s' has the misfortune of "
    4477             :                                   "lying in a range that was once used for "
    4478             :                                   "IPv4 embedding (that is, it might also be "
    4479             :                                   "represented as '%s').\n", address,
    4480             :                                   address_redux));
    4481             :                 }
    4482          25 :                 return -1;
    4483             :         }
    4484         140 :         return 0;
    4485             : }
    4486             : 
    4487             : 
    4488             : 
    4489             : /*
    4490             :  * MS-ADTS v20150630 6.1.1.2.2.2.1 Subnet Object, refers to RFC1166 and
    4491             :  * RFC2373. It specifies something seemingly indistinguishable from an RFC4632
    4492             :  * CIDR address range without saying so explicitly. Here we follow the CIDR
    4493             :  * spec.
    4494             :  *
    4495             :  * Return 0 on success, -1 on error.
    4496             :  */
    4497         210 : static int verify_cidr(const char *cidr)
    4498             : {
    4499         210 :         char *address = NULL, *slash = NULL;
    4500           0 :         bool has_colon, has_dot;
    4501           0 :         int res, ret;
    4502           0 :         unsigned long mask;
    4503         210 :         uint8_t *address_bytes = NULL;
    4504         210 :         char *address_redux = NULL;
    4505           0 :         unsigned int address_len;
    4506         210 :         TALLOC_CTX *frame = NULL;
    4507         210 :         int error = 0;
    4508             : 
    4509         210 :         DBG_DEBUG("CIDR is %s\n", cidr);
    4510         210 :         frame = talloc_stackframe();
    4511         210 :         address = talloc_strdup(frame, cidr);
    4512         210 :         if (address == NULL){
    4513           0 :                 goto error;
    4514             :         }
    4515             : 
    4516             :         /* there must be a '/' */
    4517         210 :         slash = strchr(address, '/');
    4518         210 :         if (slash == NULL){
    4519           2 :                 goto error;
    4520             :         }
    4521             :         /* terminate the address for strchr, inet_pton */
    4522         208 :         *slash = '\0';
    4523             : 
    4524         208 :         mask = smb_strtoul(slash + 1, NULL, 10, &error, SMB_STR_FULL_STR_CONV);
    4525         208 :         if (mask == 0){
    4526           6 :                 DBG_INFO("Windows does not like the zero mask, "
    4527             :                          "so nor do we: %s\n", cidr);
    4528           6 :                 goto error;
    4529             :         }
    4530             : 
    4531         202 :         if (error != 0){
    4532           6 :                 DBG_INFO("CIDR mask is not a proper integer: %s\n", cidr);
    4533           6 :                 goto error;
    4534             :         }
    4535             : 
    4536         196 :         address_bytes = talloc_size(frame, sizeof(struct in6_addr));
    4537         196 :         if (address_bytes == NULL){
    4538           0 :                 goto error;
    4539             :         }
    4540             : 
    4541         196 :         address_redux = talloc_size(frame, INET6_ADDRSTRLEN);
    4542         196 :         if (address_redux == NULL){
    4543           0 :                 goto error;
    4544             :         }
    4545             : 
    4546         196 :         DBG_INFO("found address %s, mask %lu\n", address, mask);
    4547         196 :         has_colon = (strchr(address, ':') == NULL) ? false : true;
    4548         196 :         has_dot = (strchr(address, '.') == NULL) ? false : true;
    4549         196 :         if (has_dot && has_colon){
    4550             :                 /* This seems to be an IPv4 address embedded in IPv6, which is
    4551             :                    icky. We don't support it. */
    4552           2 :                 DBG_INFO("Refusing to consider cidr '%s' with dots and colons\n",
    4553             :                           cidr);
    4554           2 :                 goto error;
    4555         194 :         } else if (has_colon){  /* looks like IPv6 */
    4556         115 :                 res = inet_pton(AF_INET6, address, address_bytes);
    4557         115 :                 if (res != 1) {
    4558          10 :                         DBG_INFO("Address in %s fails to parse as IPv6\n", cidr);
    4559          10 :                         goto error;
    4560             :                 }
    4561         105 :                 address_len = 128;
    4562         105 :                 if (check_address_roundtrip(address, AF_INET6, address_bytes,
    4563             :                                             address_redux, INET6_ADDRSTRLEN)){
    4564          25 :                         goto error;
    4565             :                 }
    4566          79 :         } else if (has_dot) {
    4567             :                 /* looks like IPv4 */
    4568          79 :                 if (strcmp(address, "0.0.0.0") == 0){
    4569           1 :                         DBG_INFO("Windows does not like the zero IPv4 address, "
    4570             :                                  "so nor do we.\n");
    4571           1 :                         goto error;
    4572             :                 }
    4573          78 :                 res = inet_pton(AF_INET, address, address_bytes);
    4574          78 :                 if (res != 1) {
    4575          18 :                         DBG_INFO("Address in %s fails to parse as IPv4\n", cidr);
    4576          18 :                         goto error;
    4577             :                 }
    4578          60 :                 address_len = 32;
    4579             : 
    4580          60 :                 if (check_address_roundtrip(address, AF_INET, address_bytes,
    4581             :                                             address_redux, INET_ADDRSTRLEN)){
    4582           0 :                         goto error;
    4583             :                 }
    4584             :         } else {
    4585             :                 /* This doesn't look like an IP address at all. */
    4586           0 :                 goto error;
    4587             :         }
    4588             : 
    4589         140 :         ret = check_cidr_zero_bits(address_bytes, address_len, mask);
    4590         140 :         talloc_free(frame);
    4591         140 :         return ret;
    4592          70 :   error:
    4593          70 :         talloc_free(frame);
    4594          70 :         return -1;
    4595             : }
    4596             : 
    4597             : 
    4598         210 : static int samldb_verify_subnet(struct samldb_ctx *ac, struct ldb_dn *dn)
    4599             : {
    4600         210 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    4601         210 :         const char *cidr = NULL;
    4602         210 :         const struct ldb_val *rdn_value = NULL;
    4603             : 
    4604         210 :         rdn_value = ldb_dn_get_rdn_val(dn);
    4605         210 :         if (rdn_value == NULL) {
    4606           0 :                 ldb_set_errstring(ldb, "samldb: ldb_dn_get_rdn_val "
    4607             :                                   "failed");
    4608           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    4609             :         }
    4610             : 
    4611         210 :         cidr = ldb_dn_escape_value(ac, *rdn_value);
    4612         210 :         DBG_INFO("looking at cidr '%s'\n", cidr);
    4613         210 :         if (cidr == NULL) {
    4614           0 :                 ldb_set_errstring(ldb,
    4615             :                                   "samldb: adding an empty subnet cidr seems wrong");
    4616           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    4617             :         }
    4618             : 
    4619         210 :         if (verify_cidr(cidr)){
    4620          97 :                 ldb_set_errstring(ldb,
    4621             :                                   "samldb: subnet value is invalid");
    4622          97 :                 return LDB_ERR_INVALID_DN_SYNTAX;
    4623             :         }
    4624             : 
    4625         113 :         return LDB_SUCCESS;
    4626             : }
    4627             : 
    4628      615040 : static char *refer_if_rodc(struct ldb_context *ldb, struct ldb_request *req,
    4629             :                            struct ldb_dn *dn)
    4630             : {
    4631      615040 :         bool rodc = false;
    4632       83756 :         struct loadparm_context *lp_ctx;
    4633       83756 :         char *referral;
    4634       83756 :         int ret;
    4635       83756 :         WERROR err;
    4636             : 
    4637     1230080 :         if (ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID) ||
    4638      615040 :             ldb_request_get_control(req, DSDB_CONTROL_DBCHECK_MODIFY_RO_REPLICA)) {
    4639           0 :                 return NULL;
    4640             :         }
    4641             : 
    4642      615040 :         ret = samdb_rodc(ldb, &rodc);
    4643      615040 :         if (ret != LDB_SUCCESS) {
    4644          19 :                 DEBUG(4, (__location__ ": unable to tell if we are an RODC\n"));
    4645          19 :                 return NULL;
    4646             :         }
    4647             : 
    4648      615021 :         if (rodc) {
    4649          23 :                 const char *domain = NULL;
    4650           0 :                 struct ldb_dn *fsmo_role_dn;
    4651           0 :                 struct ldb_dn *role_owner_dn;
    4652          23 :                 ldb_set_errstring(ldb, "RODC modify is forbidden!");
    4653          23 :                 lp_ctx = talloc_get_type(ldb_get_opaque(ldb, "loadparm"),
    4654             :                                          struct loadparm_context);
    4655             : 
    4656          23 :                 err = dsdb_get_fsmo_role_info(req, ldb, DREPL_PDC_MASTER,
    4657             :                                               &fsmo_role_dn, &role_owner_dn);
    4658          23 :                 if (W_ERROR_IS_OK(err)) {
    4659          23 :                         struct ldb_dn *server_dn = ldb_dn_copy(req, role_owner_dn);
    4660          23 :                         if (server_dn != NULL) {
    4661          23 :                                 ldb_dn_remove_child_components(server_dn, 1);
    4662             : 
    4663          23 :                                 domain = samdb_dn_to_dnshostname(ldb, req,
    4664             :                                                                  server_dn);
    4665             :                         }
    4666             :                 }
    4667          23 :                 if (domain == NULL) {
    4668           0 :                         domain = lpcfg_dnsdomain(lp_ctx);
    4669             :                 }
    4670          23 :                 referral = talloc_asprintf(req,
    4671             :                                            "ldap://%s/%s",
    4672             :                                            domain,
    4673             :                                            ldb_dn_get_linearized(dn));
    4674          23 :                 return referral;
    4675             :         }
    4676             : 
    4677      531261 :         return NULL;
    4678             : }
    4679             : 
    4680             : /*
    4681             :  * Restrict all access to sensitive attributes.
    4682             :  *
    4683             :  * We don't want to even inspect the values, so we can use the same
    4684             :  * routine for ADD and MODIFY.
    4685             :  *
    4686             :  */
    4687             : 
    4688     1131551 : static int samldb_check_sensitive_attributes(struct samldb_ctx *ac)
    4689             : {
    4690     1131551 :         struct ldb_message_element *el = NULL;
    4691     1131551 :         struct security_token *user_token = NULL;
    4692      105121 :         int ret;
    4693             : 
    4694     1131551 :         if (dsdb_module_am_system(ac->module)) {
    4695      224046 :                 return LDB_SUCCESS;
    4696             :         }
    4697             : 
    4698      889117 :         user_token = acl_user_token(ac->module);
    4699      889117 :         if (user_token == NULL) {
    4700           0 :                 return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    4701             :         }
    4702             : 
    4703      889117 :         el = ldb_msg_find_element(ac->msg, "sidHistory");
    4704      889117 :         if (el) {
    4705             :                /*
    4706             :                 * sidHistory is restricted to the (not implemented
    4707             :                 * yet in Samba) DsAddSidHistory call (direct LDB access is
    4708             :                 * as SYSTEM so will bypass this).
    4709             :                 *
    4710             :                 * If you want to modify this, say to merge domains,
    4711             :                 * directly modify the sam.ldb as root.
    4712             :                 */
    4713          16 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    4714             :                                        "sidHistory "
    4715             :                                        "(entry %s) cannot be created "
    4716             :                                        "or changed over LDAP!",
    4717          16 :                                        ldb_dn_get_linearized(ac->msg->dn));
    4718          16 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    4719             :         }
    4720             : 
    4721      889101 :         el = ldb_msg_find_element(ac->msg, "msDS-SecondaryKrbTgtNumber");
    4722      889101 :         if (el) {
    4723           0 :                 struct security_descriptor *domain_sd;
    4724          16 :                 const struct dsdb_class *objectclass = NULL;
    4725             :                 /*
    4726             :                  * msDS-SecondaryKrbTgtNumber allows the creator to
    4727             :                  * become an RODC, this is trusted as an RODC
    4728             :                  * account
    4729             :                  */
    4730          16 :                 ret = samldb_get_domain_secdesc_and_oc(ac, &domain_sd, &objectclass);
    4731          16 :                 if (ret != LDB_SUCCESS) {
    4732           8 :                         return ret;
    4733             :                 }
    4734          16 :                 ret = acl_check_extended_right(ac,
    4735             :                                                ac->module,
    4736             :                                                ac->req,
    4737             :                                                objectclass,
    4738             :                                                domain_sd,
    4739             :                                                user_token,
    4740             :                                                GUID_DRS_DS_INSTALL_REPLICA,
    4741             :                                                SEC_ADS_CONTROL_ACCESS,
    4742             :                                                NULL);
    4743          16 :                 if (ret != LDB_SUCCESS) {
    4744           8 :                         ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    4745             :                                                "msDS-SecondaryKrbTgtNumber "
    4746             :                                                "(entry %s) cannot be created "
    4747             :                                                "or changed without "
    4748             :                                                "DS-Install-Replica extended right!",
    4749           8 :                                                ldb_dn_get_linearized(ac->msg->dn));
    4750           8 :                         return ret;
    4751             :                 }
    4752             :         }
    4753             : 
    4754      889093 :         el = ldb_msg_find_element(ac->msg, "msDS-AllowedToDelegateTo");
    4755      889093 :         if (el) {
    4756             :                 /*
    4757             :                  * msDS-AllowedToDelegateTo is incredibly powerful,
    4758             :                  * given that it allows a server to become ANY USER on
    4759             :                  * the target server only listed by SPN so needs to be
    4760             :                  * protected just as the userAccountControl
    4761             :                  * UF_TRUSTED_FOR_DELEGATION is.
    4762             :                  */
    4763             : 
    4764          63 :                 bool have_priv = security_token_has_privilege(user_token,
    4765             :                                                               SEC_PRIV_ENABLE_DELEGATION);
    4766          63 :                 if (have_priv == false) {
    4767           8 :                         ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    4768             :                                                "msDS-AllowedToDelegateTo "
    4769             :                                                "(entry %s) cannot be created "
    4770             :                                                "or changed without SePrivEnableDelegation!",
    4771           8 :                                                ldb_dn_get_linearized(ac->msg->dn));
    4772           8 :                         return LDB_ERR_INSUFFICIENT_ACCESS_RIGHTS;
    4773             :                 }
    4774             :         }
    4775      802352 :         return LDB_SUCCESS;
    4776             : }
    4777             : /* add */
    4778      543093 : static int samldb_add(struct ldb_module *module, struct ldb_request *req)
    4779             : {
    4780       83665 :         struct ldb_context *ldb;
    4781       83665 :         struct samldb_ctx *ac;
    4782       83665 :         struct ldb_message_element *el;
    4783       83665 :         int ret;
    4784      543093 :         char *referral = NULL;
    4785             : 
    4786      543093 :         ldb = ldb_module_get_ctx(module);
    4787      543093 :         ldb_debug(ldb, LDB_DEBUG_TRACE, "samldb_add\n");
    4788             : 
    4789             :         /* do not manipulate our control entries */
    4790      543093 :         if (ldb_dn_is_special(req->op.add.message->dn)) {
    4791         538 :                 return ldb_next_request(module, req);
    4792             :         }
    4793             : 
    4794      542555 :         referral = refer_if_rodc(ldb, req, req->op.add.message->dn);
    4795      542555 :         if (referral != NULL) {
    4796          22 :                 ret = ldb_module_send_referral(req, referral);
    4797          22 :                 return ret;
    4798             :         }
    4799             : 
    4800      542533 :         el = ldb_msg_find_element(req->op.add.message, "userParameters");
    4801      542533 :         if (el != NULL && ldb_req_is_untrusted(req)) {
    4802           0 :                 const char *reason = "samldb_add: "
    4803             :                         "setting userParameters is not supported over LDAP, "
    4804             :                         "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
    4805           0 :                 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
    4806           0 :                 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
    4807             :         }
    4808             : 
    4809      542533 :         ac = samldb_ctx_init(module, req);
    4810      542533 :         if (ac == NULL) {
    4811           0 :                 return ldb_operr(ldb);
    4812             :         }
    4813             : 
    4814             :         /* build the new msg */
    4815      542533 :         ac->msg = ldb_msg_copy_shallow(ac, req->op.add.message);
    4816      542533 :         if (ac->msg == NULL) {
    4817           0 :                 talloc_free(ac);
    4818           0 :                 ldb_debug(ldb, LDB_DEBUG_FATAL,
    4819             :                           "samldb_add: ldb_msg_copy_shallow failed!\n");
    4820           0 :                 return ldb_operr(ldb);
    4821             :         }
    4822             : 
    4823      542533 :         ret = samldb_check_sensitive_attributes(ac);
    4824      542533 :         if (ret != LDB_SUCCESS) {
    4825          32 :                 talloc_free(ac);
    4826          32 :                 return ret;
    4827             :         }
    4828             : 
    4829      542501 :         el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
    4830      542501 :         if (el != NULL) {
    4831           9 :                 ret = samldb_fsmo_role_owner_check(ac);
    4832           9 :                 if (ret != LDB_SUCCESS) {
    4833           6 :                         return ret;
    4834             :                 }
    4835             :         }
    4836             : 
    4837      542495 :         el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
    4838      542495 :         if ((el != NULL)) {
    4839             :                 /*
    4840             :                  * We need to check whether the SPN collides with an existing
    4841             :                  * one (anywhere) including via aliases.
    4842             :                  */
    4843        1645 :                 ret = samldb_spn_uniqueness_check(ac, el);
    4844        1645 :                 if (ret != LDB_SUCCESS) {
    4845           3 :                         return ret;
    4846             :                 }
    4847             :         }
    4848             : 
    4849      542492 :         if (samdb_find_attribute(ldb, ac->msg,
    4850             :                                  "objectclass", "user") != NULL) {
    4851       30109 :                 ac->type = SAMLDB_TYPE_USER;
    4852             : 
    4853       30109 :                 ret = samldb_prim_group_trigger(ac);
    4854       30109 :                 if (ret != LDB_SUCCESS) {
    4855          26 :                         return ret;
    4856             :                 }
    4857             : 
    4858       30083 :                 ret = samldb_objectclass_trigger(ac);
    4859       30083 :                 if (ret != LDB_SUCCESS) {
    4860         110 :                         return ret;
    4861             :                 }
    4862             : 
    4863       29973 :                 return samldb_fill_object(ac);
    4864             :         }
    4865             : 
    4866      512383 :         if (samdb_find_attribute(ldb, ac->msg,
    4867             :                                  "objectclass", "group") != NULL) {
    4868        8710 :                 ac->type = SAMLDB_TYPE_GROUP;
    4869             : 
    4870        8710 :                 ret = samldb_objectclass_trigger(ac);
    4871        8710 :                 if (ret != LDB_SUCCESS) {
    4872           6 :                         return ret;
    4873             :                 }
    4874             : 
    4875        8704 :                 return samldb_fill_object(ac);
    4876             :         }
    4877             : 
    4878             :         /* perhaps a foreignSecurityPrincipal? */
    4879      503673 :         if (samdb_find_attribute(ldb, ac->msg,
    4880             :                                  "objectclass",
    4881             :                                  "foreignSecurityPrincipal") != NULL) {
    4882        3857 :                 return samldb_fill_foreignSecurityPrincipal_object(ac);
    4883             :         }
    4884             : 
    4885      499816 :         if (samdb_find_attribute(ldb, ac->msg,
    4886             :                                  "objectclass", "classSchema") != NULL) {
    4887       33722 :                 ac->type = SAMLDB_TYPE_CLASS;
    4888             : 
    4889             :                 /* If in provision, these checks are too slow to do */
    4890       33722 :                 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
    4891         882 :                         ret = samldb_schema_governsid_valid_check(ac);
    4892         882 :                         if (ret != LDB_SUCCESS) {
    4893           9 :                                 return ret;
    4894             :                         }
    4895             :                 }
    4896             : 
    4897       33713 :                 ret = samldb_schema_ldapdisplayname_valid_check(ac);
    4898       33713 :                 if (ret != LDB_SUCCESS) {
    4899           9 :                         return ret;
    4900             :                 }
    4901             : 
    4902       33704 :                 ret = samldb_schema_info_update(ac);
    4903       33704 :                 if (ret != LDB_SUCCESS) {
    4904           0 :                         talloc_free(ac);
    4905           0 :                         return ret;
    4906             :                 }
    4907             : 
    4908       33704 :                 return samldb_fill_object(ac);
    4909             :         }
    4910             : 
    4911      466094 :         if (samdb_find_attribute(ldb, ac->msg,
    4912             :                                  "objectclass", "attributeSchema") != NULL) {
    4913      184400 :                 ac->type = SAMLDB_TYPE_ATTRIBUTE;
    4914             : 
    4915             :                 /* If in provision, these checks are too slow to do */
    4916      184400 :                 if (!ldb_request_get_control(req, DSDB_CONTROL_SKIP_DUPLICATES_CHECK_OID)) {
    4917        1023 :                         ret = samldb_schema_attributeid_valid_check(ac);
    4918        1023 :                         if (ret != LDB_SUCCESS) {
    4919           9 :                                 return ret;
    4920             :                         }
    4921             : 
    4922        1014 :                         ret = samldb_schema_add_handle_linkid(ac);
    4923        1014 :                         if (ret != LDB_SUCCESS) {
    4924          36 :                                 return ret;
    4925             :                         }
    4926             : 
    4927         978 :                         ret = samldb_schema_add_handle_mapiid(ac);
    4928         978 :                         if (ret != LDB_SUCCESS) {
    4929           9 :                                 return ret;
    4930             :                         }
    4931             :                 }
    4932             : 
    4933      184346 :                 ret = samldb_schema_ldapdisplayname_valid_check(ac);
    4934      184346 :                 if (ret != LDB_SUCCESS) {
    4935          18 :                         return ret;
    4936             :                 }
    4937             : 
    4938      184328 :                 ret = samldb_schema_info_update(ac);
    4939      184328 :                 if (ret != LDB_SUCCESS) {
    4940           0 :                         talloc_free(ac);
    4941           0 :                         return ret;
    4942             :                 }
    4943             : 
    4944      184328 :                 return samldb_fill_object(ac);
    4945             :         }
    4946             : 
    4947      281694 :         if (samdb_find_attribute(ldb, ac->msg,
    4948             :                                  "objectclass", "subnet") != NULL) {
    4949         208 :                 ret = samldb_verify_subnet(ac, ac->msg->dn);
    4950         208 :                 if (ret != LDB_SUCCESS) {
    4951          96 :                         talloc_free(ac);
    4952          96 :                         return ret;
    4953             :                 }
    4954             :                 /* We are just checking the value is valid, and there are no
    4955             :                    values to fill in. */
    4956             :         }
    4957             : 
    4958      281598 :         talloc_free(ac);
    4959             : 
    4960             :         /* nothing matched, go on */
    4961      281598 :         return ldb_next_request(module, req);
    4962             : }
    4963             : 
    4964             : /* modify */
    4965      589800 : static int samldb_modify(struct ldb_module *module, struct ldb_request *req)
    4966             : {
    4967       21582 :         struct ldb_context *ldb;
    4968       21582 :         struct samldb_ctx *ac;
    4969       21582 :         struct ldb_message_element *el, *el2;
    4970       21582 :         struct ldb_control *is_undelete;
    4971      589800 :         bool modified = false;
    4972       21582 :         int ret;
    4973             : 
    4974      589800 :         if (ldb_dn_is_special(req->op.mod.message->dn)) {
    4975             :                 /* do not manipulate our control entries */
    4976         715 :                 return ldb_next_request(module, req);
    4977             :         }
    4978             : 
    4979      589085 :         ldb = ldb_module_get_ctx(module);
    4980             : 
    4981             :         /*
    4982             :          * we are going to need some special handling if in Undelete call.
    4983             :          * Since tombstone_reanimate module will restore certain attributes,
    4984             :          * we need to relax checks for: sAMAccountType, primaryGroupID
    4985             :          */
    4986      589085 :         is_undelete = ldb_request_get_control(req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID);
    4987             : 
    4988             :         /* make sure that "objectSid" is not specified */
    4989      589085 :         el = ldb_msg_find_element(req->op.mod.message, "objectSid");
    4990      589085 :         if (el != NULL) {
    4991          15 :                 if (ldb_request_get_control(req, LDB_CONTROL_PROVISION_OID) == NULL) {
    4992          15 :                         ldb_set_errstring(ldb,
    4993             :                                           "samldb: objectSid must not be specified!");
    4994          15 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    4995             :                 }
    4996             :         }
    4997      589070 :         if (is_undelete == NULL) {
    4998             :                 /* make sure that "sAMAccountType" is not specified */
    4999      588805 :                 el = ldb_msg_find_element(req->op.mod.message, "sAMAccountType");
    5000      588805 :                 if (el != NULL) {
    5001          15 :                         ldb_set_errstring(ldb,
    5002             :                                           "samldb: sAMAccountType must not be specified!");
    5003          15 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    5004             :                 }
    5005             :         }
    5006             :         /* make sure that "isCriticalSystemObject" is not specified */
    5007      589055 :         el = ldb_msg_find_element(req->op.mod.message, "isCriticalSystemObject");
    5008      589055 :         if (el != NULL) {
    5009         390 :                 if (ldb_request_get_control(req, LDB_CONTROL_RELAX_OID) == NULL) {
    5010           1 :                         ldb_set_errstring(ldb,
    5011             :                                           "samldb: isCriticalSystemObject must not be specified!");
    5012           1 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    5013             :                 }
    5014             :         }
    5015             : 
    5016             :         /* msDS-IntId is not allowed to be modified
    5017             :          * except when modification comes from replication */
    5018      589054 :         if (ldb_msg_find_element(req->op.mod.message, "msDS-IntId")) {
    5019          36 :                 if (!ldb_request_get_control(req,
    5020             :                                              DSDB_CONTROL_REPLICATED_UPDATE_OID)) {
    5021          36 :                         return LDB_ERR_CONSTRAINT_VIOLATION;
    5022             :                 }
    5023             :         }
    5024             : 
    5025      589018 :         el = ldb_msg_find_element(req->op.mod.message, "userParameters");
    5026      589018 :         if (el != NULL && ldb_req_is_untrusted(req)) {
    5027           0 :                 const char *reason = "samldb: "
    5028             :                         "setting userParameters is not supported over LDAP, "
    5029             :                         "see https://bugzilla.samba.org/show_bug.cgi?id=8077";
    5030           0 :                 ldb_debug(ldb, LDB_DEBUG_WARNING, "%s", reason);
    5031           0 :                 return ldb_error(ldb, LDB_ERR_CONSTRAINT_VIOLATION, reason);
    5032             :         }
    5033             : 
    5034      589018 :         ac = samldb_ctx_init(module, req);
    5035      589018 :         if (ac == NULL) {
    5036           0 :                 return ldb_operr(ldb);
    5037             :         }
    5038             : 
    5039             :         /* build the new msg */
    5040      589018 :         ac->msg = ldb_msg_copy_shallow(ac, req->op.mod.message);
    5041      589018 :         if (ac->msg == NULL) {
    5042           0 :                 talloc_free(ac);
    5043           0 :                 ldb_debug(ldb, LDB_DEBUG_FATAL,
    5044             :                           "samldb_modify: ldb_msg_copy_shallow failed!\n");
    5045           0 :                 return ldb_operr(ldb);
    5046             :         }
    5047             : 
    5048      589018 :         ret = samldb_check_sensitive_attributes(ac);
    5049      589018 :         if (ret != LDB_SUCCESS) {
    5050           0 :                 talloc_free(ac);
    5051           0 :                 return ret;
    5052             :         }
    5053             : 
    5054      589018 :         if (is_undelete == NULL) {
    5055      588753 :                 el = ldb_msg_find_element(ac->msg, "primaryGroupID");
    5056      588753 :                 if (el != NULL) {
    5057         202 :                         ret = samldb_prim_group_trigger(ac);
    5058         202 :                         if (ret != LDB_SUCCESS) {
    5059          14 :                                 return ret;
    5060             :                         }
    5061             :                 }
    5062             :         }
    5063             : 
    5064      589004 :         el = ldb_msg_find_element(ac->msg, "userAccountControl");
    5065      589004 :         if (el != NULL) {
    5066       15984 :                 modified = true;
    5067       15984 :                 ret = samldb_user_account_control_change(ac);
    5068       15984 :                 if (ret != LDB_SUCCESS) {
    5069         181 :                         return ret;
    5070             :                 }
    5071             :         }
    5072             : 
    5073      588823 :         el = ldb_msg_find_element(ac->msg, "pwdLastSet");
    5074      588823 :         if (el != NULL) {
    5075         321 :                 modified = true;
    5076         321 :                 ret = samldb_pwd_last_set_change(ac);
    5077         321 :                 if (ret != LDB_SUCCESS) {
    5078           6 :                         return ret;
    5079             :                 }
    5080             :         }
    5081             : 
    5082      588817 :         el = ldb_msg_find_element(ac->msg, "lockoutTime");
    5083      588817 :         if (el != NULL) {
    5084         189 :                 modified = true;
    5085         189 :                 ret = samldb_lockout_time(ac);
    5086         189 :                 if (ret != LDB_SUCCESS) {
    5087           0 :                         return ret;
    5088             :                 }
    5089             :         }
    5090             : 
    5091      588817 :         el = ldb_msg_find_element(ac->msg, "groupType");
    5092      588817 :         if (el != NULL) {
    5093         146 :                 modified = true;
    5094         146 :                 ret = samldb_group_type_change(ac);
    5095         146 :                 if (ret != LDB_SUCCESS) {
    5096          33 :                         return ret;
    5097             :                 }
    5098             :         }
    5099             : 
    5100      588784 :         el = ldb_msg_find_element(ac->msg, "sAMAccountName");
    5101      588784 :         if (el != NULL) {
    5102          10 :                 uint32_t user_account_control;
    5103         912 :                 struct ldb_result *res = NULL;
    5104         912 :                 const char * const attrs[] = { "userAccountControl",
    5105             :                                                "objectclass",
    5106             :                                                NULL };
    5107         922 :                 ret = dsdb_module_search_dn(ac->module,
    5108             :                                             ac,
    5109             :                                             &res,
    5110         912 :                                             ac->msg->dn,
    5111             :                                             attrs,
    5112             :                                             DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
    5113             :                                             ac->req);
    5114         912 :                 if (ret != LDB_SUCCESS) {
    5115          46 :                         return ret;
    5116             :                 }
    5117          10 :                 user_account_control
    5118         912 :                         = ldb_msg_find_attr_as_uint(res->msgs[0],
    5119             :                                                     "userAccountControl",
    5120             :                                                     0);
    5121             : 
    5122         912 :                 if ((user_account_control
    5123         912 :                      & UF_TRUST_ACCOUNT_MASK) != 0) {
    5124         310 :                         ac->need_trailing_dollar = true;
    5125             : 
    5126         602 :                 } else if (samdb_find_attribute(ldb,
    5127         602 :                                                 res->msgs[0],
    5128             :                                                 "objectclass",
    5129             :                                                 "computer")
    5130             :                            != NULL) {
    5131          12 :                         ac->need_trailing_dollar = true;
    5132             :                 }
    5133             : 
    5134         912 :                 ret = samldb_sam_accountname_valid_check(ac);
    5135         912 :                 if (ret != LDB_SUCCESS) {
    5136          46 :                         return ret;
    5137             :                 }
    5138             :         }
    5139             : 
    5140      588738 :         el = ldb_msg_find_element(ac->msg, "userPrincipalName");
    5141      588738 :         if (el != NULL) {
    5142         424 :                 ret = samldb_sam_account_upn_clash(ac);
    5143         424 :                 if (ret != LDB_SUCCESS) {
    5144          16 :                         talloc_free(ac);
    5145          16 :                         return ret;
    5146             :                 }
    5147             :         }
    5148             : 
    5149      588722 :         el = ldb_msg_find_element(ac->msg, "ldapDisplayName");
    5150      588722 :         if (el != NULL) {
    5151          29 :                 ret = samldb_schema_ldapdisplayname_valid_check(ac);
    5152          29 :                 if (ret != LDB_SUCCESS) {
    5153          18 :                         return ret;
    5154             :                 }
    5155             :         }
    5156             : 
    5157      588704 :         el = ldb_msg_find_element(ac->msg, "attributeID");
    5158      588704 :         if (el != NULL) {
    5159          27 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    5160             :                                        "Once set, attributeID values may not be modified");
    5161          27 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
    5162             :         }
    5163             : 
    5164      588677 :         el = ldb_msg_find_element(ac->msg, "governsID");
    5165      588677 :         if (el != NULL) {
    5166          18 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    5167             :                                        "Once set, governsID values may not be modified");
    5168          18 :                 return LDB_ERR_CONSTRAINT_VIOLATION;
    5169             :         }
    5170             : 
    5171      588659 :         el = ldb_msg_find_element(ac->msg, "member");
    5172      588659 :         if (el != NULL) {
    5173        5161 :                 struct ldb_control *fix_link_sid_ctrl = NULL;
    5174             : 
    5175        5161 :                 fix_link_sid_ctrl = ldb_request_get_control(ac->req,
    5176             :                                         DSDB_CONTROL_DBCHECK_FIX_LINK_DN_SID);
    5177        5161 :                 if (fix_link_sid_ctrl == NULL) {
    5178        5159 :                         ret = samldb_member_check(ac);
    5179        5159 :                         if (ret != LDB_SUCCESS) {
    5180           3 :                                 return ret;
    5181             :                         }
    5182             :                 }
    5183             :         }
    5184             : 
    5185      588656 :         el = ldb_msg_find_element(ac->msg, "description");
    5186      588656 :         if (el != NULL) {
    5187        1037 :                 ret = samldb_description_check(ac, &modified);
    5188        1037 :                 if (ret != LDB_SUCCESS) {
    5189           0 :                         return ret;
    5190             :                 }
    5191             :         }
    5192             : 
    5193      588656 :         el = ldb_msg_find_element(ac->msg, "dNSHostName");
    5194      588656 :         el2 = ldb_msg_find_element(ac->msg, "sAMAccountName");
    5195      588656 :         if ((el != NULL) || (el2 != NULL)) {
    5196        1611 :                 modified = true;
    5197             :                 /*
    5198             :                  * samldb_service_principal_names_change() might add SPN
    5199             :                  * changes to the request, so this must come before the SPN
    5200             :                  * uniqueness check below.
    5201             :                  *
    5202             :                  * Note we ALSO have to do the SPN uniqueness check inside
    5203             :                  * samldb_service_principal_names_change(), because it does a
    5204             :                  * subrequest to do requested SPN modifications *before* its
    5205             :                  * automatic ones are added.
    5206             :                  */
    5207        1611 :                 ret = samldb_service_principal_names_change(ac);
    5208        1611 :                 if (ret != LDB_SUCCESS) {
    5209           0 :                         return ret;
    5210             :                 }
    5211             :         }
    5212             : 
    5213      588656 :         el = ldb_msg_find_element(ac->msg, "servicePrincipalName");
    5214      588656 :         if ((el != NULL)) {
    5215             :                 /*
    5216             :                  * We need to check whether the SPN collides with an existing
    5217             :                  * one (anywhere) including via aliases.
    5218             :                  */
    5219        2178 :                 modified = true;
    5220        2178 :                 ret = samldb_spn_uniqueness_check(ac, el);
    5221        2178 :                 if (ret != LDB_SUCCESS) {
    5222          78 :                         return ret;
    5223             :                 }
    5224             :         }
    5225             : 
    5226      588578 :         el = ldb_msg_find_element(ac->msg, "fSMORoleOwner");
    5227      588578 :         if (el != NULL) {
    5228        1278 :                 ret = samldb_fsmo_role_owner_check(ac);
    5229        1278 :                 if (ret != LDB_SUCCESS) {
    5230           6 :                         return ret;
    5231             :                 }
    5232             :         }
    5233             : 
    5234      588572 :         if (modified) {
    5235         277 :                 struct ldb_request *child_req;
    5236             : 
    5237             :                 /* Now perform the real modifications as a child request */
    5238       20364 :                 ret = ldb_build_mod_req(&child_req, ldb, ac,
    5239       20087 :                                         ac->msg,
    5240             :                                         req->controls,
    5241             :                                         req, dsdb_next_callback,
    5242             :                                         req);
    5243       20087 :                 LDB_REQ_SET_LOCATION(child_req);
    5244       20087 :                 if (ret != LDB_SUCCESS) {
    5245           0 :                         return ret;
    5246             :                 }
    5247             : 
    5248       20087 :                 return ldb_next_request(module, child_req);
    5249             :         }
    5250             : 
    5251      568485 :         talloc_free(ac);
    5252             : 
    5253             :         /* no change which interests us, go on */
    5254      568485 :         return ldb_next_request(module, req);
    5255             : }
    5256             : 
    5257             : /* delete */
    5258             : 
    5259       72484 : static int samldb_prim_group_users_check(struct samldb_ctx *ac)
    5260             : {
    5261         159 :         struct ldb_context *ldb;
    5262         159 :         struct dom_sid *sid;
    5263         159 :         uint32_t rid;
    5264         159 :         NTSTATUS status;
    5265         159 :         int ret;
    5266       72484 :         struct ldb_result *res = NULL;
    5267       72484 :         struct ldb_result *res_users = NULL;
    5268       72484 :         const char * const attrs[] = { "objectSid", "isDeleted", NULL };
    5269       72484 :         const char * const noattrs[] = { NULL };
    5270             : 
    5271       72484 :         ldb = ldb_module_get_ctx(ac->module);
    5272             : 
    5273             :         /* Finds out the SID/RID of the SAM object */
    5274       72484 :         ret = dsdb_module_search_dn(ac->module, ac, &res, ac->req->op.del.dn,
    5275             :                                         attrs,
    5276             :                                         DSDB_FLAG_NEXT_MODULE | DSDB_SEARCH_SHOW_DELETED,
    5277             :                                         ac->req);
    5278       72484 :         if (ret != LDB_SUCCESS) {
    5279           0 :                 return ret;
    5280             :         }
    5281             : 
    5282       72484 :         if (ldb_msg_check_string_attribute(res->msgs[0], "isDeleted", "TRUE")) {
    5283           7 :                 return LDB_SUCCESS;
    5284             :         }
    5285             : 
    5286       72470 :         sid = samdb_result_dom_sid(ac, res->msgs[0], "objectSid");
    5287       72470 :         if (sid == NULL) {
    5288             :                 /* No SID - it might not be a SAM object - therefore ok */
    5289       39835 :                 return LDB_SUCCESS;
    5290             :         }
    5291       32574 :         status = dom_sid_split_rid(ac, sid, NULL, &rid);
    5292       32574 :         if (!NT_STATUS_IS_OK(status)) {
    5293           0 :                 return ldb_operr(ldb);
    5294             :         }
    5295       32574 :         if (rid == 0) {
    5296             :                 /* Special object (security principal?) */
    5297           0 :                 return LDB_SUCCESS;
    5298             :         }
    5299             :         /* do not allow deletion of well-known sids */
    5300       32592 :         if (rid < DSDB_SAMDB_MINIMUM_ALLOWED_RID &&
    5301          18 :             (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) == NULL)) {
    5302          18 :                 return LDB_ERR_OTHER;
    5303             :         }
    5304             : 
    5305             :         /* Deny delete requests from groups which are primary ones */
    5306       32556 :         ret = dsdb_module_search(ac->module, ac, &res_users,
    5307             :                                  ldb_get_default_basedn(ldb),
    5308             :                                  LDB_SCOPE_SUBTREE, noattrs,
    5309             :                                  DSDB_FLAG_NEXT_MODULE,
    5310             :                                  ac->req,
    5311             :                                  "(&(primaryGroupID=%u)(objectClass=user))", rid);
    5312       32556 :         if (ret != LDB_SUCCESS) {
    5313           0 :                 return ret;
    5314             :         }
    5315       32556 :         if (res_users->count > 0) {
    5316           3 :                 ldb_asprintf_errstring(ldb_module_get_ctx(ac->module),
    5317             :                                        "Refusing to delete %s, as it "
    5318             :                                        "is still the primaryGroupID "
    5319             :                                        "for %u users",
    5320           3 :                                        ldb_dn_get_linearized(res->msgs[0]->dn),
    5321           3 :                                        res_users->count);
    5322             : 
    5323             :                 /*
    5324             :                  * Yes, this seems very wrong, but we have a test
    5325             :                  * for this exact error code in sam.py
    5326             :                  */
    5327           3 :                 return LDB_ERR_ENTRY_ALREADY_EXISTS;
    5328             :         }
    5329             : 
    5330       32462 :         return LDB_SUCCESS;
    5331             : }
    5332             : 
    5333       72486 : static int samldb_delete(struct ldb_module *module, struct ldb_request *req)
    5334             : {
    5335         159 :         struct samldb_ctx *ac;
    5336       72486 :         char *referral = NULL;
    5337         159 :         int ret;
    5338         159 :         struct ldb_context *ldb;
    5339             : 
    5340       72486 :         if (ldb_dn_is_special(req->op.del.dn)) {
    5341             :                 /* do not manipulate our control entries */
    5342           1 :                 return ldb_next_request(module, req);
    5343             :         }
    5344             : 
    5345       72485 :         ldb = ldb_module_get_ctx(module);
    5346             : 
    5347       72485 :         referral = refer_if_rodc(ldb, req, req->op.del.dn);
    5348       72485 :         if (referral != NULL) {
    5349           1 :                 ret = ldb_module_send_referral(req, referral);
    5350           1 :                 return ret;
    5351             :         }
    5352             : 
    5353       72484 :         ac = samldb_ctx_init(module, req);
    5354       72484 :         if (ac == NULL) {
    5355           0 :                 return ldb_operr(ldb_module_get_ctx(module));
    5356             :         }
    5357             : 
    5358       72484 :         ret = samldb_prim_group_users_check(ac);
    5359       72484 :         if (ret != LDB_SUCCESS) {
    5360          21 :                 return ret;
    5361             :         }
    5362             : 
    5363       72463 :         talloc_free(ac);
    5364             : 
    5365       72463 :         return ldb_next_request(module, req);
    5366             : }
    5367             : 
    5368             : /* rename */
    5369             : 
    5370        1479 : static int check_rename_constraints(struct ldb_message *msg,
    5371             :                                     struct samldb_ctx *ac,
    5372             :                                     struct ldb_dn *olddn, struct ldb_dn *newdn)
    5373             : {
    5374        1479 :         struct ldb_context *ldb = ldb_module_get_ctx(ac->module);
    5375           6 :         struct ldb_dn *dn1, *dn2, *nc_root;
    5376           6 :         int32_t systemFlags;
    5377        1479 :         bool move_op = false;
    5378        1479 :         bool rename_op = false;
    5379           6 :         int ret;
    5380             : 
    5381             :         /* Skip the checks if old and new DN are the same, or if we have the
    5382             :          * relax control specified or if the returned objects is already
    5383             :          * deleted and needs only to be moved for consistency. */
    5384             : 
    5385        1479 :         if (ldb_dn_compare(olddn, newdn) == 0) {
    5386           6 :                 return LDB_SUCCESS;
    5387             :         }
    5388        1473 :         if (ldb_request_get_control(ac->req, LDB_CONTROL_RELAX_OID) != NULL) {
    5389          21 :                 return LDB_SUCCESS;
    5390             :         }
    5391             : 
    5392        1452 :         if (ldb_msg_find_attr_as_bool(msg, "isDeleted", false)) {
    5393             :                 /*
    5394             :                  * check originating request if we are supposed
    5395             :                  * to "see" this record in first place.
    5396             :                  */
    5397           2 :                 if (ldb_request_get_control(ac->req, LDB_CONTROL_SHOW_DELETED_OID) == NULL) {
    5398           1 :                         return LDB_ERR_NO_SUCH_OBJECT;
    5399             :                 }
    5400           1 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    5401             :         }
    5402             : 
    5403             :         /* Objects under CN=System */
    5404             : 
    5405        1450 :         dn1 = samdb_system_container_dn(ldb, ac);
    5406        1450 :         if (dn1 == NULL) return ldb_oom(ldb);
    5407             : 
    5408        1451 :         if ((ldb_dn_compare_base(dn1, olddn) == 0) &&
    5409           1 :             (ldb_dn_compare_base(dn1, newdn) != 0)) {
    5410           1 :                 talloc_free(dn1);
    5411           1 :                 ldb_asprintf_errstring(ldb,
    5412             :                                        "subtree_rename: Cannot move/rename %s. Objects under CN=System have to stay under it!",
    5413             :                                        ldb_dn_get_linearized(olddn));
    5414           1 :                 return LDB_ERR_OTHER;
    5415             :         }
    5416             : 
    5417        1449 :         talloc_free(dn1);
    5418             : 
    5419             :         /* LSA objects */
    5420             : 
    5421        2898 :         if ((samdb_find_attribute(ldb, msg, "objectClass", "secret") != NULL) ||
    5422        1449 :             (samdb_find_attribute(ldb, msg, "objectClass", "trustedDomain") != NULL)) {
    5423           0 :                 ldb_asprintf_errstring(ldb,
    5424             :                                        "subtree_rename: Cannot move/rename %s. It's an LSA-specific object!",
    5425             :                                        ldb_dn_get_linearized(olddn));
    5426           0 :                 return LDB_ERR_UNWILLING_TO_PERFORM;
    5427             :         }
    5428             : 
    5429             :         /* subnet objects */
    5430        1449 :         if (samdb_find_attribute(ldb, msg, "objectclass", "subnet") != NULL) {
    5431           2 :                 ret = samldb_verify_subnet(ac, newdn);
    5432           2 :                 if (ret != LDB_SUCCESS) {
    5433           1 :                         return ret;
    5434             :                 }
    5435             :         }
    5436             : 
    5437             :         /* systemFlags */
    5438             : 
    5439        1448 :         dn1 = ldb_dn_get_parent(ac, olddn);
    5440        1448 :         if (dn1 == NULL) return ldb_oom(ldb);
    5441        1448 :         dn2 = ldb_dn_get_parent(ac, newdn);
    5442        1448 :         if (dn2 == NULL) return ldb_oom(ldb);
    5443             : 
    5444        1448 :         if (ldb_dn_compare(dn1, dn2) == 0) {
    5445         917 :                 rename_op = true;
    5446             :         } else {
    5447         525 :                 move_op = true;
    5448             :         }
    5449             : 
    5450        1448 :         talloc_free(dn1);
    5451        1448 :         talloc_free(dn2);
    5452             : 
    5453        1448 :         systemFlags = ldb_msg_find_attr_as_int(msg, "systemFlags", 0);
    5454             : 
    5455             :         /* Fetch name context */
    5456             : 
    5457        1448 :         ret = dsdb_find_nc_root(ldb, ac, olddn, &nc_root);
    5458        1448 :         if (ret != LDB_SUCCESS) {
    5459           0 :                 return ret;
    5460             :         }
    5461             : 
    5462        1448 :         if (ldb_dn_compare(nc_root, ldb_get_schema_basedn(ldb)) == 0) {
    5463           8 :                 if (move_op) {
    5464           0 :                         ldb_asprintf_errstring(ldb,
    5465             :                                                "subtree_rename: Cannot move %s within schema partition",
    5466             :                                                ldb_dn_get_linearized(olddn));
    5467           0 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    5468             :                 }
    5469           8 :                 if (rename_op &&
    5470           8 :                     (systemFlags & SYSTEM_FLAG_SCHEMA_BASE_OBJECT) != 0) {
    5471           1 :                         ldb_asprintf_errstring(ldb,
    5472             :                                                "subtree_rename: Cannot rename %s within schema partition",
    5473             :                                                ldb_dn_get_linearized(olddn));
    5474           1 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    5475             :                 }
    5476        1440 :         } else if (ldb_dn_compare(nc_root, ldb_get_config_basedn(ldb)) == 0) {
    5477          12 :                 if (move_op &&
    5478           4 :                     (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_MOVE) == 0) {
    5479             :                         /* Here we have to do more: control the
    5480             :                          * "ALLOW_LIMITED_MOVE" flag. This means that the
    5481             :                          * grand-grand-parents of two objects have to be equal
    5482             :                          * in order to perform the move (this is used for
    5483             :                          * moving "server" objects in the "sites" container). */
    5484           4 :                         bool limited_move =
    5485           4 :                                 systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_LIMITED_MOVE;
    5486             : 
    5487           4 :                         if (limited_move) {
    5488           0 :                                 dn1 = ldb_dn_copy(ac, olddn);
    5489           0 :                                 if (dn1 == NULL) return ldb_oom(ldb);
    5490           0 :                                 dn2 = ldb_dn_copy(ac, newdn);
    5491           0 :                                 if (dn2 == NULL) return ldb_oom(ldb);
    5492             : 
    5493           0 :                                 limited_move &= ldb_dn_remove_child_components(dn1, 3);
    5494           0 :                                 limited_move &= ldb_dn_remove_child_components(dn2, 3);
    5495           0 :                                 limited_move &= ldb_dn_compare(dn1, dn2) == 0;
    5496             : 
    5497           0 :                                 talloc_free(dn1);
    5498           0 :                                 talloc_free(dn2);
    5499             :                         }
    5500             : 
    5501           4 :                         if (!limited_move
    5502           4 :                             && ldb_request_get_control(ac->req, DSDB_CONTROL_RESTORE_TOMBSTONE_OID) == NULL) {
    5503           2 :                                 ldb_asprintf_errstring(ldb,
    5504             :                                                        "subtree_rename: Cannot move %s to %s in config partition",
    5505             :                                                        ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
    5506           2 :                                 return LDB_ERR_UNWILLING_TO_PERFORM;
    5507             :                         }
    5508             :                 }
    5509          10 :                 if (rename_op &&
    5510           8 :                     (systemFlags & SYSTEM_FLAG_CONFIG_ALLOW_RENAME) == 0) {
    5511           1 :                         ldb_asprintf_errstring(ldb,
    5512             :                                                "subtree_rename: Cannot rename %s to %s within config partition",
    5513             :                                                ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
    5514           1 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    5515             :                 }
    5516        1428 :         } else if (ldb_dn_compare(nc_root, ldb_get_default_basedn(ldb)) == 0) {
    5517        1424 :                 if (move_op &&
    5518         521 :                     (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_MOVE) != 0) {
    5519           1 :                         ldb_asprintf_errstring(ldb,
    5520             :                                                "subtree_rename: Cannot move %s to %s - DISALLOW_MOVE set",
    5521             :                                                ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
    5522           1 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    5523             :                 }
    5524        1423 :                 if (rename_op &&
    5525         903 :                     (systemFlags & SYSTEM_FLAG_DOMAIN_DISALLOW_RENAME) != 0) {
    5526           1 :                         ldb_asprintf_errstring(ldb,
    5527             :                                                        "subtree_rename: Cannot rename %s to %s - DISALLOW_RENAME set",
    5528             :                                                ldb_dn_get_linearized(olddn), ldb_dn_get_linearized(newdn));
    5529           1 :                         return LDB_ERR_UNWILLING_TO_PERFORM;
    5530             :                 }
    5531             :         }
    5532             : 
    5533        1442 :         talloc_free(nc_root);
    5534             : 
    5535        1442 :         return LDB_SUCCESS;
    5536             : }
    5537             : 
    5538             : 
    5539        2951 : static int samldb_rename_search_base_callback(struct ldb_request *req,
    5540             :                                                struct ldb_reply *ares)
    5541             : {
    5542          15 :         struct samldb_ctx *ac;
    5543          15 :         int ret;
    5544             : 
    5545        2951 :         ac = talloc_get_type(req->context, struct samldb_ctx);
    5546             : 
    5547        2951 :         if (!ares) {
    5548           0 :                 return ldb_module_done(ac->req, NULL, NULL,
    5549             :                                         LDB_ERR_OPERATIONS_ERROR);
    5550             :         }
    5551        2951 :         if (ares->error != LDB_SUCCESS) {
    5552           0 :                 return ldb_module_done(ac->req, ares->controls,
    5553             :                                         ares->response, ares->error);
    5554             :         }
    5555             : 
    5556        2951 :         switch (ares->type) {
    5557        1479 :         case LDB_REPLY_ENTRY:
    5558             :                 /*
    5559             :                  * This is the root entry of the originating move
    5560             :                  * respectively rename request. It has been already
    5561             :                  * stored in the list using "subtree_rename_search()".
    5562             :                  * Only this one is subject to constraint checking.
    5563             :                  */
    5564        1485 :                 ret = check_rename_constraints(ares->message, ac,
    5565        1473 :                                                ac->req->op.rename.olddn,
    5566        1479 :                                                ac->req->op.rename.newdn);
    5567        1479 :                 if (ret != LDB_SUCCESS) {
    5568          10 :                         return ldb_module_done(ac->req, NULL, NULL,
    5569             :                                                ret);
    5570             :                 }
    5571        1463 :                 break;
    5572             : 
    5573           0 :         case LDB_REPLY_REFERRAL:
    5574             :                 /* ignore */
    5575           0 :                 break;
    5576             : 
    5577        1472 :         case LDB_REPLY_DONE:
    5578             : 
    5579             :                 /*
    5580             :                  * Great, no problem with the rename, so go ahead as
    5581             :                  * if we never were here
    5582             :                  */
    5583        1472 :                 ret = ldb_next_request(ac->module, ac->req);
    5584        1472 :                 talloc_free(ares);
    5585        1472 :                 return ret;
    5586             :         }
    5587             : 
    5588        1469 :         talloc_free(ares);
    5589        1469 :         return LDB_SUCCESS;
    5590             : }
    5591             : 
    5592             : 
    5593             : /* rename */
    5594        1482 : static int samldb_rename(struct ldb_module *module, struct ldb_request *req)
    5595             : {
    5596           9 :         struct ldb_context *ldb;
    5597           9 :         static const char * const attrs[] = { "objectClass", "systemFlags",
    5598             :                                               "isDeleted", NULL };
    5599           9 :         struct ldb_request *search_req;
    5600           9 :         struct samldb_ctx *ac;
    5601           9 :         int ret;
    5602             : 
    5603        1482 :         if (ldb_dn_is_special(req->op.rename.olddn)) { /* do not manipulate our control entries */
    5604           0 :                 return ldb_next_request(module, req);
    5605             :         }
    5606             : 
    5607        1482 :         ldb = ldb_module_get_ctx(module);
    5608             : 
    5609        1482 :         ac = samldb_ctx_init(module, req);
    5610        1482 :         if (!ac) {
    5611           0 :                 return ldb_oom(ldb);
    5612             :         }
    5613             : 
    5614        1482 :         ret = ldb_build_search_req(&search_req, ldb, ac,
    5615             :                                    req->op.rename.olddn,
    5616             :                                    LDB_SCOPE_BASE,
    5617             :                                    "(objectClass=*)",
    5618             :                                    attrs,
    5619             :                                    NULL,
    5620             :                                    ac,
    5621             :                                    samldb_rename_search_base_callback,
    5622             :                                    req);
    5623        1482 :         LDB_REQ_SET_LOCATION(search_req);
    5624        1482 :         if (ret != LDB_SUCCESS) {
    5625           0 :                 return ret;
    5626             :         }
    5627             : 
    5628        1482 :         ret = ldb_request_add_control(search_req, LDB_CONTROL_SHOW_RECYCLED_OID,
    5629             :                                       true, NULL);
    5630        1482 :         if (ret != LDB_SUCCESS) {
    5631           0 :                 return ret;
    5632             :         }
    5633             : 
    5634        1482 :         return ldb_next_request(ac->module, search_req);
    5635             : }
    5636             : 
    5637             : /* extended */
    5638             : 
    5639          37 : static int samldb_extended_allocate_rid_pool(struct ldb_module *module, struct ldb_request *req)
    5640             : {
    5641          37 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    5642           0 :         struct dsdb_fsmo_extended_op *exop;
    5643           0 :         int ret;
    5644             : 
    5645          37 :         exop = talloc_get_type(req->op.extended.data,
    5646             :                                struct dsdb_fsmo_extended_op);
    5647          37 :         if (!exop) {
    5648           0 :                 ldb_set_errstring(ldb,
    5649             :                                   "samldb_extended_allocate_rid_pool: invalid extended data");
    5650           0 :                 return LDB_ERR_PROTOCOL_ERROR;
    5651             :         }
    5652             : 
    5653          37 :         ret = ridalloc_allocate_rid_pool_fsmo(module, exop, req);
    5654          37 :         if (ret != LDB_SUCCESS) {
    5655           0 :                 return ret;
    5656             :         }
    5657             : 
    5658          37 :         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
    5659             : }
    5660             : 
    5661         995 : static int samldb_extended_allocate_rid(struct ldb_module *module, struct ldb_request *req)
    5662             : {
    5663         995 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    5664           0 :         struct dsdb_extended_allocate_rid *exop;
    5665           0 :         int ret;
    5666             : 
    5667         995 :         exop = talloc_get_type(req->op.extended.data,
    5668             :                                struct dsdb_extended_allocate_rid);
    5669         995 :         if (!exop) {
    5670           0 :                 ldb_set_errstring(ldb,
    5671             :                                   "samldb_extended_allocate_rid: invalid extended data");
    5672           0 :                 return LDB_ERR_PROTOCOL_ERROR;
    5673             :         }
    5674             : 
    5675         995 :         ret = ridalloc_allocate_rid(module, &exop->rid, req);
    5676         995 :         if (ret != LDB_SUCCESS) {
    5677           2 :                 return ret;
    5678             :         }
    5679             : 
    5680         993 :         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
    5681             : }
    5682             : 
    5683          39 : static int samldb_extended_create_own_rid_set(struct ldb_module *module, struct ldb_request *req)
    5684             : {
    5685          39 :         struct ldb_context *ldb = ldb_module_get_ctx(module);
    5686           0 :         int ret;
    5687           0 :         struct ldb_dn *dn;
    5688             : 
    5689          39 :         if (req->op.extended.data != NULL) {
    5690           0 :                 ldb_set_errstring(ldb,
    5691             :                                   "samldb_extended_create_own_rid_set: invalid extended data (should be NULL)");
    5692           0 :                 return LDB_ERR_PROTOCOL_ERROR;
    5693             :         }
    5694             : 
    5695          39 :         ret = ridalloc_create_own_rid_set(module, req,
    5696             :                                           &dn, req);
    5697          39 :         if (ret != LDB_SUCCESS) {
    5698           1 :                 return ret;
    5699             :         }
    5700             : 
    5701          38 :         return ldb_module_done(req, NULL, NULL, LDB_SUCCESS);
    5702             : }
    5703             : 
    5704     1280937 : static int samldb_extended(struct ldb_module *module, struct ldb_request *req)
    5705             : {
    5706     1280937 :         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID_POOL) == 0) {
    5707          37 :                 return samldb_extended_allocate_rid_pool(module, req);
    5708             :         }
    5709             : 
    5710     1280900 :         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_ALLOCATE_RID) == 0) {
    5711         995 :                 return samldb_extended_allocate_rid(module, req);
    5712             :         }
    5713             : 
    5714     1279905 :         if (strcmp(req->op.extended.oid, DSDB_EXTENDED_CREATE_OWN_RID_SET) == 0) {
    5715          39 :                 return samldb_extended_create_own_rid_set(module, req);
    5716             :         }
    5717             : 
    5718     1279866 :         return ldb_next_request(module, req);
    5719             : }
    5720             : 
    5721             : 
    5722             : static const struct ldb_module_ops ldb_samldb_module_ops = {
    5723             :         .name          = "samldb",
    5724             :         .add           = samldb_add,
    5725             :         .modify        = samldb_modify,
    5726             :         .del           = samldb_delete,
    5727             :         .rename        = samldb_rename,
    5728             :         .extended      = samldb_extended
    5729             : };
    5730             : 
    5731             : 
    5732        5908 : int ldb_samldb_module_init(const char *version)
    5733             : {
    5734        5908 :         LDB_MODULE_CHECK_VERSION(version);
    5735        5908 :         return ldb_register_module(&ldb_samldb_module_ops);
    5736             : }

Generated by: LCOV version 1.14