Ignore:
Timestamp:
Nov 14, 2012, 12:59:34 PM (13 years ago)
Author:
Silvan Scherrer
Message:

Samba Server: update vendor to 3.6.0

Location:
vendor/current/source4/dsdb/common
Files:
8 added
1 deleted
1 edited

Legend:

Unmodified
Added
Removed
  • vendor/current/source4/dsdb/common/util.c

    r414 r740  
    2525#include "events/events.h"
    2626#include "ldb.h"
     27#include "ldb_module.h"
    2728#include "ldb_errors.h"
    2829#include "../lib/util/util_ldb.h"
     
    3839#include "libcli/auth/libcli_auth.h"
    3940#include "librpc/gen_ndr/ndr_drsblobs.h"
     41#include "system/locale.h"
     42#include "lib/util/tsort.h"
     43#include "dsdb/common/util.h"
     44#include "lib/socket/socket.h"
     45#include "librpc/gen_ndr/irpc.h"
     46#include "libds/common/flag_mapping.h"
    4047
    4148/*
     
    106113        }
    107114
    108         return samdb_result_string(res[0], attr_name, NULL);
     115        return ldb_msg_find_attr_as_string(res[0], attr_name, NULL);
    109116}
    110117
     
    192199{
    193200        va_list ap;
    194         struct ldb_message **res;
    195         const char * const attrs[] = { NULL };
     201        const char *attrs[] = { NULL };
    196202        int ret;
    197203
    198204        va_start(ap, format);
    199         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
     205        ret = gendb_search_v(sam_ldb, mem_ctx, basedn, NULL, attrs, format, ap);
    200206        va_end(ap);
    201207
     
    207213  search the sam for a single integer attribute in exactly 1 record
    208214*/
    209 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
     215unsigned int samdb_search_uint(struct ldb_context *sam_ldb,
    210216                         TALLOC_CTX *mem_ctx,
    211                          uint_t default_value,
     217                         unsigned int default_value,
    212218                         struct ldb_dn *basedn,
    213219                         const char *attr_name,
     
    229235        }
    230236
    231         return samdb_result_uint(res[0], attr_name, default_value);
     237        return ldb_msg_find_attr_as_uint(res[0], attr_name, default_value);
    232238}
    233239
     
    257263        }
    258264
    259         return samdb_result_int64(res[0], attr_name, default_value);
     265        return ldb_msg_find_attr_as_int64(res[0], attr_name, default_value);
    260266}
    261267
     
    303309
    304310        for (i=0;i<count;i++) {
    305                 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
     311                (*strs)[i] = ldb_msg_find_attr_as_string(res[i], attr_name, NULL);
    306312        }
    307313        (*strs)[count] = NULL;
    308314
    309315        return count;
    310 }
    311 
    312 /*
    313   pull a uint from a result set.
    314 */
    315 uint_t samdb_result_uint(const struct ldb_message *msg, const char *attr, uint_t default_value)
    316 {
    317         return ldb_msg_find_attr_as_uint(msg, attr, default_value);
    318 }
    319 
    320 /*
    321   pull a (signed) int64 from a result set.
    322 */
    323 int64_t samdb_result_int64(const struct ldb_message *msg, const char *attr, int64_t default_value)
    324 {
    325         return ldb_msg_find_attr_as_int64(msg, attr, default_value);
    326 }
    327 
    328 /*
    329   pull a string from a result set.
    330 */
    331 const char *samdb_result_string(const struct ldb_message *msg, const char *attr,
    332                                 const char *default_value)
    333 {
    334         return ldb_msg_find_attr_as_string(msg, attr, default_value);
    335316}
    336317
     
    369350                                     const char *attr)
    370351{
     352        bool ok;
    371353        const struct ldb_val *v;
    372354        struct dom_sid *sid;
    373         enum ndr_err_code ndr_err;
    374355        v = ldb_msg_find_ldb_val(msg, attr);
    375356        if (v == NULL) {
     
    380361                return NULL;
    381362        }
    382         ndr_err = ndr_pull_struct_blob(v, sid, NULL, sid,
    383                                        (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
    384         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     363        ok = sid_blob_parse(*v, sid);
     364        if (!ok) {
    385365                talloc_free(sid);
    386366                return NULL;
     
    395375{
    396376        const struct ldb_val *v;
    397         enum ndr_err_code ndr_err;
    398377        struct GUID guid;
    399         TALLOC_CTX *mem_ctx;
    400 
    401         ZERO_STRUCT(guid);
     378        NTSTATUS status;
    402379
    403380        v = ldb_msg_find_ldb_val(msg, attr);
    404         if (!v) return guid;
    405 
    406         mem_ctx = talloc_named_const(NULL, 0, "samdb_result_guid");
    407         if (!mem_ctx) return guid;
    408         ndr_err = ndr_pull_struct_blob(v, mem_ctx, NULL, &guid,
    409                                        (ndr_pull_flags_fn_t)ndr_pull_GUID);
    410         talloc_free(mem_ctx);
    411         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    412                 return guid;
     381        if (!v) return GUID_zero();
     382
     383        status = GUID_from_ndr_blob(v, &guid);
     384        if (!NT_STATUS_IS_OK(status)) {
     385                return GUID_zero();
    413386        }
    414387
     
    432405  pull a NTTIME in a result set.
    433406*/
    434 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
     407NTTIME samdb_result_nttime(const struct ldb_message *msg, const char *attr,
     408                           NTTIME default_value)
    435409{
    436410        return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
     
    443417 * cause windows 2008 and newer version to fail for SMB requests
    444418 */
    445 NTTIME samdb_result_last_logoff(struct ldb_message *msg)
     419NTTIME samdb_result_last_logoff(const struct ldb_message *msg)
    446420{
    447421        NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "lastLogoff",0);
     
    465439 * the rest of the code.
    466440 */
    467 NTTIME samdb_result_account_expires(struct ldb_message *msg)
     441NTTIME samdb_result_account_expires(const struct ldb_message *msg)
    468442{
    469443        NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
     
    475449        return ret;
    476450}
    477 
    478 /*
    479   pull a uint64_t from a result set.
    480 */
    481 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
    482 {
    483         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
    484 }
    485 
    486451
    487452/*
     
    495460                                          const char *attr)
    496461{
    497         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
     462        uint64_t attr_time = ldb_msg_find_attr_as_uint64(msg, attr, 0);
    498463        int64_t minPwdAge;
    499464
     
    520485                                          struct ldb_message *msg)
    521486{
    522         uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
    523         uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
     487        int64_t attr_time = ldb_msg_find_attr_as_int64(msg, "pwdLastSet", 0);
     488        uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg,
     489                                                                "userAccountControl",
     490                                                                0);
    524491        int64_t maxPwdAge;
    525492
     
    533500                return 0;
    534501        }
    535 
    536         maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
     502        if (attr_time == -1) {
     503                return 0x7FFFFFFFFFFFFFFFULL;
     504        }
     505
     506        maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn,
     507                                       "maxPwdAge", NULL);
    537508        if (maxPwdAge == 0) {
    538509                return 0x7FFFFFFFFFFFFFFFULL;
     
    559530
    560531/*
    561   pull an array of samr_Password structutres from a result set.
    562 */
    563 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
     532  pull an array of samr_Password structures from a result set.
     533*/
     534unsigned int samdb_result_hashes(TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
    564535                           const char *attr, struct samr_Password **hashes)
    565536{
    566         uint_t count = 0;
     537        unsigned int count, i;
    567538        const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
    568         int i;
    569539
    570540        *hashes = NULL;
     
    589559}
    590560
    591 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 
     561NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg,
    592562                                struct samr_Password **lm_pwd, struct samr_Password **nt_pwd)
    593563{
    594564        struct samr_Password *lmPwdHash, *ntPwdHash;
    595565        if (nt_pwd) {
    596                 int num_nt;
     566                unsigned int num_nt;
    597567                num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
    598568                if (num_nt == 0) {
     
    608578                 * authentication, that we never use the LM hash, even
    609579                 * if we store it */
    610                 if (lp_lanman_auth(lp_ctx)) {
    611                         int num_lm;
     580                if (lpcfg_lanman_auth(lp_ctx)) {
     581                        unsigned int num_lm;
    612582                        num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
    613583                        if (num_lm == 0) {
     
    631601{
    632602        struct samr_LogonHours hours;
    633         const int units_per_week = 168;
     603        size_t units_per_week = 168;
    634604        const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
     605
    635606        ZERO_STRUCT(hours);
    636         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
     607
     608        if (val) {
     609                units_per_week = val->length * 8;
     610        }
     611
     612        hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week/8);
    637613        if (!hours.bits) {
    638614                return hours;
    639615        }
    640616        hours.units_per_week = units_per_week;
    641         memset(hours.bits, 0xFF, units_per_week);
     617        memset(hours.bits, 0xFF, units_per_week/8);
    642618        if (val) {
    643                 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
    644         }
     619                memcpy(hours.bits, val->data, val->length);
     620        }
     621
    645622        return hours;
    646623}
     
    691668                return s;
    692669        }
    693         s.length = s.size = val->length/2;
     670        s.length = s.size = val->length;
    694671        memcpy(s.array, val->data, val->length);
    695672
     
    707684                                                 const char *name, const char *value)
    708685{
    709         int i;
     686        unsigned int i;
    710687        struct ldb_message_element *el = ldb_msg_find_element(msg, name);
    711688
     
    723700}
    724701
    725 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
    726 {
    727         if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
    728                 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
    729         }
    730         return LDB_SUCCESS;
    731 }
    732 
    733702int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
    734703{
     
    740709        }
    741710
    742         return samdb_msg_add_string(ldb, msg, msg, name, set_value);
    743 }
    744 
    745 
    746 
    747 /*
    748   add a string element to a message
    749 */
    750 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    751                          const char *attr_name, const char *str)
    752 {
    753         char *s = talloc_strdup(mem_ctx, str);
    754         char *a = talloc_strdup(mem_ctx, attr_name);
    755         if (s == NULL || a == NULL) {
    756                 return LDB_ERR_OPERATIONS_ERROR;
    757         }
    758         return ldb_msg_add_string(msg, a, s);
     711        return ldb_msg_add_string(msg, name, set_value);
    759712}
    760713
     
    769722
    770723        ndr_err = ndr_push_struct_blob(&v, mem_ctx,
    771                                        lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
    772724                                       sid,
    773725                                       (ndr_push_flags_fn_t)ndr_push_dom_sid);
    774726        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    775                 return -1;
     727                return ldb_operr(sam_ldb);
    776728        }
    777729        return ldb_msg_add_value(msg, attr_name, &v, NULL);
     
    786738{
    787739        /* we use an empty replace rather than a delete, as it allows for
    788            samdb_replace() to be used everywhere */
     740           dsdb_replace() to be used everywhere */
    789741        return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
    790742}
    791743
    792744/*
    793   add a add attribute value to a message
    794 */
    795 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    796                          const char *attr_name, const char *value)
     745  add an add attribute value to a message or enhance an existing attribute
     746  which has the same name and the add flag set.
     747*/
     748int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
     749                         struct ldb_message *msg, const char *attr_name,
     750                         const char *value)
    797751{
    798752        struct ldb_message_element *el;
    799         char *a, *v;
    800         int ret;
    801         a = talloc_strdup(mem_ctx, attr_name);
    802         if (a == NULL)
    803                 return -1;
     753        struct ldb_val val, *vals;
     754        char *v;
     755        unsigned int i;
     756        bool found = false;
     757        int ret;
     758
    804759        v = talloc_strdup(mem_ctx, value);
    805         if (v == NULL)
    806                 return -1;
    807         ret = ldb_msg_add_string(msg, a, v);
    808         if (ret != 0)
    809                 return ret;
    810         el = ldb_msg_find_element(msg, a);
    811         if (el == NULL)
    812                 return -1;
    813         el->flags = LDB_FLAG_MOD_ADD;
    814         return 0;
    815 }
    816 
    817 /*
    818   add a delete attribute value to a message
    819 */
    820 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    821                          const char *attr_name, const char *value)
     760        if (v == NULL) {
     761                return ldb_oom(sam_ldb);
     762        }
     763
     764        val.data = (uint8_t *) v;
     765        val.length = strlen(v);
     766
     767        if (val.length == 0) {
     768                /* allow empty strings as non-existent attributes */
     769                return LDB_SUCCESS;
     770        }
     771
     772        for (i = 0; i < msg->num_elements; i++) {
     773                el = &msg->elements[i];
     774                if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
     775                    (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_ADD)) {
     776                        found = true;
     777                        break;
     778                }
     779        }
     780        if (!found) {
     781                ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_ADD,
     782                                        &el);
     783                if (ret != LDB_SUCCESS) {
     784                        return ret;
     785                }
     786        }
     787
     788        vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
     789                              el->num_values + 1);
     790        if (vals == NULL) {
     791                return ldb_oom(sam_ldb);
     792        }
     793        el->values = vals;
     794        el->values[el->num_values] = val;
     795        ++(el->num_values);
     796
     797        return LDB_SUCCESS;
     798}
     799
     800/*
     801  add a delete attribute value to a message or enhance an existing attribute
     802  which has the same name and the delete flag set.
     803*/
     804int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
     805                         struct ldb_message *msg, const char *attr_name,
     806                         const char *value)
    822807{
    823808        struct ldb_message_element *el;
    824         char *a, *v;
    825         int ret;
    826         a = talloc_strdup(mem_ctx, attr_name);
    827         if (a == NULL)
    828                 return -1;
     809        struct ldb_val val, *vals;
     810        char *v;
     811        unsigned int i;
     812        bool found = false;
     813        int ret;
     814
    829815        v = talloc_strdup(mem_ctx, value);
    830         if (v == NULL)
    831                 return -1;
    832         ret = ldb_msg_add_string(msg, a, v);
    833         if (ret != 0)
    834                 return ret;
    835         el = ldb_msg_find_element(msg, a);
    836         if (el == NULL)
    837                 return -1;
    838         el->flags = LDB_FLAG_MOD_DELETE;
    839         return 0;
     816        if (v == NULL) {
     817                return ldb_oom(sam_ldb);
     818        }
     819
     820        val.data = (uint8_t *) v;
     821        val.length = strlen(v);
     822
     823        if (val.length == 0) {
     824                /* allow empty strings as non-existent attributes */
     825                return LDB_SUCCESS;
     826        }
     827
     828        for (i = 0; i < msg->num_elements; i++) {
     829                el = &msg->elements[i];
     830                if ((ldb_attr_cmp(el->name, attr_name) == 0) &&
     831                    (LDB_FLAG_MOD_TYPE(el->flags) == LDB_FLAG_MOD_DELETE)) {
     832                        found = true;
     833                        break;
     834                }
     835        }
     836        if (!found) {
     837                ret = ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_DELETE,
     838                                        &el);
     839                if (ret != LDB_SUCCESS) {
     840                        return ret;
     841                }
     842        }
     843
     844        vals = talloc_realloc(msg->elements, el->values, struct ldb_val,
     845                              el->num_values + 1);
     846        if (vals == NULL) {
     847                return ldb_oom(sam_ldb);
     848        }
     849        el->values = vals;
     850        el->values[el->num_values] = val;
     851        ++(el->num_values);
     852
     853        return LDB_SUCCESS;
    840854}
    841855
     
    847861{
    848862        const char *s = talloc_asprintf(mem_ctx, "%d", v);
    849         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
    850 }
    851 
    852 /*
    853   add a uint_t element to a message
    854 */
     863        if (s == NULL) {
     864                return ldb_oom(sam_ldb);
     865        }
     866        return ldb_msg_add_string(msg, attr_name, s);
     867}
     868
     869/*
     870 * Add an unsigned int element to a message
     871 *
     872 * The issue here is that we have not yet first cast to int32_t explicitly,
     873 * before we cast to an signed int to printf() into the %d or cast to a
     874 * int64_t before we then cast to a long long to printf into a %lld.
     875 *
     876 * There are *no* unsigned integers in Active Directory LDAP, even the RID
     877 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
     878 * (See the schema, and the syntax definitions in schema_syntax.c).
     879 *
     880 */
    855881int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    856                        const char *attr_name, uint_t v)
    857 {
    858         const char *s = talloc_asprintf(mem_ctx, "%u", v);
    859         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
     882                       const char *attr_name, unsigned int v)
     883{
     884        return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, (int)v);
    860885}
    861886
     
    867892{
    868893        const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
    869         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
    870 }
    871 
    872 /*
    873   add a uint64_t element to a message
    874 */
     894        if (s == NULL) {
     895                return ldb_oom(sam_ldb);
     896        }
     897        return ldb_msg_add_string(msg, attr_name, s);
     898}
     899
     900/*
     901 * Add an unsigned int64_t (uint64_t) element to a message
     902 *
     903 * The issue here is that we have not yet first cast to int32_t explicitly,
     904 * before we cast to an signed int to printf() into the %d or cast to a
     905 * int64_t before we then cast to a long long to printf into a %lld.
     906 *
     907 * There are *no* unsigned integers in Active Directory LDAP, even the RID
     908 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
     909 * (See the schema, and the syntax definitions in schema_syntax.c).
     910 *
     911 */
    875912int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    876913                        const char *attr_name, uint64_t v)
    877914{
    878         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
    879         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
     915        return samdb_msg_add_int64(sam_ldb, mem_ctx, msg, attr_name, (int64_t)v);
    880916}
    881917
     
    884920*/
    885921int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    886                        const char *attr_name, struct samr_Password *hash)
     922                       const char *attr_name, const struct samr_Password *hash)
    887923{
    888924        struct ldb_val val;
    889925        val.data = talloc_memdup(mem_ctx, hash->hash, 16);
    890926        if (!val.data) {
    891                 return -1;
     927                return ldb_oom(sam_ldb);
    892928        }
    893929        val.length = 16;
     
    898934  add a samr_Password array to a message
    899935*/
    900 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    901                          const char *attr_name, struct samr_Password *hashes, uint_t count)
     936int samdb_msg_add_hashes(struct ldb_context *ldb,
     937                         TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     938                         const char *attr_name, struct samr_Password *hashes,
     939                         unsigned int count)
    902940{
    903941        struct ldb_val val;
    904         int i;
     942        unsigned int i;
    905943        val.data = talloc_array_size(mem_ctx, 16, count);
    906944        val.length = count*16;
    907945        if (!val.data) {
    908                 return -1;
     946                return ldb_oom(ldb);
    909947        }
    910948        for (i=0;i<count;i++) {
     
    942980{
    943981        struct ldb_val val;
    944         val.length = parameters->length * 2;
     982        val.length = parameters->length;
    945983        val.data = (uint8_t *)parameters->array;
    946984        return ldb_msg_add_value(msg, attr_name, &val, NULL);
    947 }
    948 /*
    949   add a general value element to a message
    950 */
    951 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
    952                               const char *attr_name, const struct ldb_val *val)
    953 {
    954         return ldb_msg_add_value(msg, attr_name, val, NULL);
    955985}
    956986
     
    9821012                el->num_values = 0;
    9831013        }
    984         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
    985 }
    986 
    987 /*
    988   replace elements in a record
    989 */
    990 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
    991 {
    992         int i;
    993 
    994         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
    995         for (i=0;i<msg->num_elements;i++) {
    996                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
    997         }
    998 
    999         /* modify the samdb record */
    1000         return ldb_modify(sam_ldb, msg);
     1014        return ldb_msg_add_string(msg, attr_name, str);
     1015}
     1016
     1017/*
     1018 * sets a signed integer in a message
     1019 */
     1020int samdb_msg_set_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
     1021                      struct ldb_message *msg, const char *attr_name, int v)
     1022{
     1023        struct ldb_message_element *el;
     1024
     1025        el = ldb_msg_find_element(msg, attr_name);
     1026        if (el) {
     1027                el->num_values = 0;
     1028        }
     1029        return samdb_msg_add_int(sam_ldb, mem_ctx, msg, attr_name, v);
     1030}
     1031
     1032/*
     1033 * Sets an unsigned int element in a message
     1034 *
     1035 * The issue here is that we have not yet first cast to int32_t explicitly,
     1036 * before we cast to an signed int to printf() into the %d or cast to a
     1037 * int64_t before we then cast to a long long to printf into a %lld.
     1038 *
     1039 * There are *no* unsigned integers in Active Directory LDAP, even the RID
     1040 * allocations and ms-DS-Secondary-KrbTgt-Number are *signed* quantities.
     1041 * (See the schema, and the syntax definitions in schema_syntax.c).
     1042 *
     1043 */
     1044int samdb_msg_set_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx,
     1045                       struct ldb_message *msg, const char *attr_name,
     1046                       unsigned int v)
     1047{
     1048        struct ldb_message_element *el;
     1049
     1050        el = ldb_msg_find_element(msg, attr_name);
     1051        if (el) {
     1052                el->num_values = 0;
     1053        }
     1054        return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, v);
     1055}
     1056
     1057/*
     1058 * Handle ldb_request in transaction
     1059 */
     1060static int dsdb_autotransaction_request(struct ldb_context *sam_ldb,
     1061                                        struct ldb_request *req)
     1062{
     1063        int ret;
     1064
     1065        ret = ldb_transaction_start(sam_ldb);
     1066        if (ret != LDB_SUCCESS) {
     1067                return ret;
     1068        }
     1069
     1070        ret = ldb_request(sam_ldb, req);
     1071        if (ret == LDB_SUCCESS) {
     1072                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     1073        }
     1074
     1075        if (ret == LDB_SUCCESS) {
     1076                return ldb_transaction_commit(sam_ldb);
     1077        }
     1078        ldb_transaction_cancel(sam_ldb);
     1079
     1080        return ret;
    10011081}
    10021082
     
    10131093}
    10141094
    1015 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx)
    1016 {
    1017         return ldb_get_default_basedn(sam_ctx);
    1018 }
    1019 
    1020 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx)
    1021 {
    1022         return ldb_get_config_basedn(sam_ctx);
    1023 }
    1024 
    1025 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx)
    1026 {
    1027         return ldb_get_schema_basedn(sam_ctx);
    1028 }
    1029 
    1030 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx)
    1031 {
    1032         return ldb_get_root_basedn(sam_ctx);
     1095struct ldb_dn *samdb_aggregate_schema_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
     1096{
     1097        struct ldb_dn *schema_dn = ldb_get_schema_basedn(sam_ctx);
     1098        struct ldb_dn *aggregate_dn;
     1099        if (!schema_dn) {
     1100                return NULL;
     1101        }
     1102
     1103        aggregate_dn = ldb_dn_copy(mem_ctx, schema_dn);
     1104        if (!aggregate_dn) {
     1105                return NULL;
     1106        }
     1107        if (!ldb_dn_add_child_fmt(aggregate_dn, "CN=Aggregate")) {
     1108                return NULL;
     1109        }
     1110        return aggregate_dn;
    10331111}
    10341112
     
    10371115        struct ldb_dn *new_dn;
    10381116
    1039         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
     1117        new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
    10401118        if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
    10411119                talloc_free(new_dn);
     
    10451123}
    10461124
     1125struct ldb_dn *samdb_infrastructure_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
     1126{
     1127       struct ldb_dn *new_dn;
     1128
     1129       new_dn = ldb_dn_copy(mem_ctx, ldb_get_default_basedn(sam_ctx));
     1130       if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Infrastructure")) {
     1131               talloc_free(new_dn);
     1132               return NULL;
     1133       }
     1134       return new_dn;
     1135}
     1136
    10471137struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
    10481138{
    10491139        struct ldb_dn *new_dn;
    10501140
    1051         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
     1141        new_dn = ldb_dn_copy(mem_ctx, ldb_get_config_basedn(sam_ctx));
    10521142        if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
    10531143                talloc_free(new_dn);
     
    11081198
    11091199failed:
    1110         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
    11111200        talloc_free(tmp_ctx);
    11121201        return NULL;
     1202}
     1203
     1204/*
     1205  get domain sid from cache
     1206*/
     1207const struct dom_sid *samdb_domain_sid_cache_only(struct ldb_context *ldb)
     1208{
     1209        return (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
    11131210}
    11141211
     
    11501247}
    11511248
    1152 /* Obtain the short name of the flexible single master operator
    1153  * (FSMO), such as the PDC Emulator */
    1154 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
    1155                              const char *attr)
    1156 {
    1157         /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
    1158         struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
    1159         const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
    1160         const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
    1161 
    1162         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
    1163                 /* Ensure this matches the format.  This gives us a
    1164                  * bit more confidence that a 'cn' value will be a
    1165                  * ascii string */
    1166                 return NULL;
    1167         }
    1168         if (val) {
    1169                 return (char *)val->data;
    1170         }
    1171         return NULL;
     1249bool samdb_set_ntds_settings_dn(struct ldb_context *ldb, struct ldb_dn *ntds_settings_dn_in)
     1250{
     1251        TALLOC_CTX *tmp_ctx;
     1252        struct ldb_dn *ntds_settings_dn_new;
     1253        struct ldb_dn *ntds_settings_dn_old;
     1254
     1255        /* see if we have a cached copy */
     1256        ntds_settings_dn_old = talloc_get_type(ldb_get_opaque(ldb,
     1257                                                              "cache.ntds_settings_dn"), struct ldb_dn);
     1258
     1259        tmp_ctx = talloc_new(ldb);
     1260        if (tmp_ctx == NULL) {
     1261                goto failed;
     1262        }
     1263
     1264        ntds_settings_dn_new = ldb_dn_copy(tmp_ctx, ntds_settings_dn_in);
     1265        if (!ntds_settings_dn_new) {
     1266                goto failed;
     1267        }
     1268
     1269        /* cache the domain_sid in the ldb */
     1270        if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", ntds_settings_dn_new) != LDB_SUCCESS) {
     1271                goto failed;
     1272        }
     1273
     1274        talloc_steal(ldb, ntds_settings_dn_new);
     1275        talloc_free(tmp_ctx);
     1276        talloc_free(ntds_settings_dn_old);
     1277
     1278        return true;
     1279
     1280failed:
     1281        DEBUG(1,("Failed to set our NTDS Settings DN in the ldb!\n"));
     1282        talloc_free(tmp_ctx);
     1283        return false;
    11721284}
    11731285
     
    11841296
    11851297        /* see if we have a cached copy */
    1186         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
     1298        settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.ntds_settings_dn");
    11871299        if (settings_dn) {
    11881300                return settings_dn;
     
    12081320
    12091321        /* cache the domain_sid in the ldb */
    1210         if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
     1322        if (ldb_set_opaque(ldb, "cache.ntds_settings_dn", settings_dn) != LDB_SUCCESS) {
    12111323                goto failed;
    12121324        }
     
    14221534{
    14231535        struct ldb_dn *server_dn;
     1536        struct ldb_dn *servers_dn;
    14241537        struct ldb_dn *server_site_dn;
    14251538
     1539        /* TODO: there must be a saner way to do this!! */
    14261540        server_dn = samdb_server_dn(ldb, mem_ctx);
    14271541        if (!server_dn) return NULL;
    14281542
    1429         server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
    1430 
     1543        servers_dn = ldb_dn_get_parent(mem_ctx, server_dn);
    14311544        talloc_free(server_dn);
     1545        if (!servers_dn) return NULL;
     1546
     1547        server_site_dn = ldb_dn_get_parent(mem_ctx, servers_dn);
     1548        talloc_free(servers_dn);
     1549
    14321550        return server_site_dn;
    14331551}
    14341552
    14351553/*
    1436  * This works out if we are running on a supported forest/domain function
    1437  * level. Basically this means that we don't support mixed/interim (NT 4 DC
    1438  * support) levels.
    1439  * If errmsg isn't NULL we write in an adequate error message for printing out
    1440  * to the screen.
    1441  */
    1442 bool samdb_is_capable_dc(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    1443         char **errmsg)
    1444 {
    1445         int32_t level_forest, level_domain, level_domain_mixed;
    1446         bool ret = true;
    1447 
    1448         level_forest = (int32_t) samdb_search_int64(ldb, mem_ctx, -1,
    1449                 samdb_partitions_dn(ldb, mem_ctx), "msDS-Behavior-Version",
    1450                 NULL);
    1451         level_domain = (int32_t) samdb_search_int64(ldb, mem_ctx, -1,
    1452                 samdb_base_dn(ldb), "msDS-Behavior-Version", NULL);
    1453         level_domain_mixed = (int32_t) samdb_search_int64(ldb, mem_ctx, -1,
    1454                 samdb_base_dn(ldb), "nTMixedDomain", NULL);
    1455 
    1456         if (errmsg != NULL)
    1457                 *errmsg = talloc_strdup(mem_ctx, "");
    1458 
    1459         if (level_forest == -1 || level_domain == -1 || level_domain_mixed == -1) {
    1460                 ret = false;
    1461                 if (errmsg != NULL)
    1462                         *errmsg = talloc_strdup_append(*errmsg,
    1463                                 "\nATTENTION: Invalid values for forest and/or domain function level!"
    1464                         );
    1465         }
    1466 
    1467         if (level_forest == DS_DOMAIN_FUNCTION_2003_MIXED) {
    1468                 ret = false;
    1469                 if (errmsg != NULL)
    1470                         *errmsg = talloc_strdup_append(*errmsg,
    1471                                 "\nATTENTION: You run SAMBA 4 on the 2003 with mixed domains (NT4 DC support) forest level. This isn't supported!"
    1472                         );
    1473         }
    1474         if ((level_domain == DS_DOMAIN_FUNCTION_2000 && level_domain_mixed != 0)
    1475                 || level_domain == DS_DOMAIN_FUNCTION_2003_MIXED) {
    1476                 ret = false;
    1477                 if (errmsg != NULL)
    1478                         *errmsg = talloc_strdup_append(*errmsg,
    1479                                 "\nATTENTION: You run SAMBA 4 on a mixed/interim (NT4 DC support) domain level. This isn't supported!"
    1480                         );
    1481         }
    1482 
    1483         if ((!ret) && (errmsg != NULL)) {
    1484                 *errmsg = talloc_strdup_append(*errmsg,
    1485                         "\nPlease raise the domain and/or forest level to an adequate value. Use for this the 'domainlevel' tool, the MS AD MMC tools or manipulate the needed attributes directly."
    1486                 );
    1487         }
    1488 
     1554  find the site name from a computers DN record
     1555 */
     1556int samdb_find_site_for_computer(struct ldb_context *ldb,
     1557                                 TALLOC_CTX *mem_ctx, struct ldb_dn *computer_dn,
     1558                                 const char **site_name)
     1559{
     1560        int ret;
     1561        struct ldb_dn *dn;
     1562        const struct ldb_val *rdn_val;
     1563
     1564        *site_name = NULL;
     1565
     1566        ret = samdb_reference_dn(ldb, mem_ctx, computer_dn, "serverReferenceBL", &dn);
     1567        if (ret != LDB_SUCCESS) {
     1568                return ret;
     1569        }
     1570
     1571        if (!ldb_dn_remove_child_components(dn, 2)) {
     1572                talloc_free(dn);
     1573                return LDB_ERR_INVALID_DN_SYNTAX;
     1574        }
     1575
     1576        rdn_val = ldb_dn_get_rdn_val(dn);
     1577        if (rdn_val == NULL) {
     1578                return LDB_ERR_OPERATIONS_ERROR;
     1579        }
     1580
     1581        (*site_name) = talloc_strndup(mem_ctx, (const char *)rdn_val->data, rdn_val->length);
     1582        talloc_free(dn);
     1583        if (!*site_name) {
     1584                return LDB_ERR_OPERATIONS_ERROR;
     1585        }
     1586        return LDB_SUCCESS;
     1587}
     1588
     1589/*
     1590  find the NTDS GUID from a computers DN record
     1591 */
     1592int samdb_find_ntdsguid_for_computer(struct ldb_context *ldb, struct ldb_dn *computer_dn,
     1593                                     struct GUID *ntds_guid)
     1594{
     1595        int ret;
     1596        struct ldb_dn *dn;
     1597
     1598        *ntds_guid = GUID_zero();
     1599
     1600        ret = samdb_reference_dn(ldb, ldb, computer_dn, "serverReferenceBL", &dn);
     1601        if (ret != LDB_SUCCESS) {
     1602                return ret;
     1603        }
     1604
     1605        if (!ldb_dn_add_child_fmt(dn, "CN=NTDS Settings")) {
     1606                talloc_free(dn);
     1607                return LDB_ERR_OPERATIONS_ERROR;
     1608        }
     1609
     1610        ret = dsdb_find_guid_by_dn(ldb, dn, ntds_guid);
     1611        talloc_free(dn);
    14891612        return ret;
     1613}
     1614
     1615/*
     1616  find a 'reference' DN that points at another object
     1617  (eg. serverReference, rIDManagerReference etc)
     1618 */
     1619int samdb_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *base,
     1620                       const char *attribute, struct ldb_dn **dn)
     1621{
     1622        const char *attrs[2];
     1623        struct ldb_result *res;
     1624        int ret;
     1625
     1626        attrs[0] = attribute;
     1627        attrs[1] = NULL;
     1628
     1629        ret = dsdb_search(ldb, mem_ctx, &res, base, LDB_SCOPE_BASE, attrs, DSDB_SEARCH_ONE_ONLY, NULL);
     1630        if (ret != LDB_SUCCESS) {
     1631                return ret;
     1632        }
     1633
     1634        *dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, res->msgs[0], attribute);
     1635        if (!*dn) {
     1636                if (!ldb_msg_find_element(res->msgs[0], attribute)) {
     1637                        ldb_asprintf_errstring(ldb, "Cannot find attribute %s of %s to calculate reference dn", attribute,
     1638                                               ldb_dn_get_linearized(base));
     1639                } else {
     1640                        ldb_asprintf_errstring(ldb, "Cannot interpret attribute %s of %s as a dn", attribute,
     1641                                               ldb_dn_get_linearized(base));
     1642                }
     1643                talloc_free(res);
     1644                return LDB_ERR_NO_SUCH_ATTRIBUTE;
     1645        }
     1646
     1647        talloc_free(res);
     1648        return LDB_SUCCESS;
     1649}
     1650
     1651/*
     1652  find our machine account via the serverReference attribute in the
     1653  server DN
     1654 */
     1655int samdb_server_reference_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
     1656{
     1657        struct ldb_dn *server_dn;
     1658        int ret;
     1659
     1660        server_dn = samdb_server_dn(ldb, mem_ctx);
     1661        if (server_dn == NULL) {
     1662                return LDB_ERR_NO_SUCH_OBJECT;
     1663        }
     1664
     1665        ret = samdb_reference_dn(ldb, mem_ctx, server_dn, "serverReference", dn);
     1666        talloc_free(server_dn);
     1667
     1668        return ret;
     1669}
     1670
     1671/*
     1672  find the RID Manager$ DN via the rIDManagerReference attribute in the
     1673  base DN
     1674 */
     1675int samdb_rid_manager_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
     1676{
     1677        return samdb_reference_dn(ldb, mem_ctx, ldb_get_default_basedn(ldb),
     1678                                  "rIDManagerReference", dn);
     1679}
     1680
     1681/*
     1682  find the RID Set DN via the rIDSetReferences attribute in our
     1683  machine account DN
     1684 */
     1685int samdb_rid_set_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn **dn)
     1686{
     1687        struct ldb_dn *server_ref_dn;
     1688        int ret;
     1689
     1690        ret = samdb_server_reference_dn(ldb, mem_ctx, &server_ref_dn);
     1691        if (ret != LDB_SUCCESS) {
     1692                return ret;
     1693        }
     1694        ret = samdb_reference_dn(ldb, mem_ctx, server_ref_dn, "rIDSetReferences", dn);
     1695        talloc_free(server_ref_dn);
     1696        return ret;
     1697}
     1698
     1699const char *samdb_server_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
     1700{
     1701        const struct ldb_val *val = ldb_dn_get_rdn_val(samdb_server_site_dn(ldb,
     1702                                                                            mem_ctx));
     1703
     1704        if (val == NULL) {
     1705                return NULL;
     1706        }
     1707
     1708        return (const char *) val->data;
     1709}
     1710
     1711/*
     1712 * Finds the client site by using the client's IP address.
     1713 * The "subnet_name" returns the name of the subnet if parameter != NULL
     1714 */
     1715const char *samdb_client_site_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
     1716                                   const char *ip_address, char **subnet_name)
     1717{
     1718        const char *attrs[] = { "cn", "siteObject", NULL };
     1719        struct ldb_dn *sites_container_dn, *subnets_dn, *sites_dn;
     1720        struct ldb_result *res;
     1721        const struct ldb_val *val;
     1722        const char *site_name = NULL, *l_subnet_name = NULL;
     1723        const char *allow_list[2] = { NULL, NULL };
     1724        unsigned int i, count;
     1725        int cnt, ret;
     1726
     1727        /*
     1728         * if we don't have a client ip e.g. ncalrpc
     1729         * the server site is the client site
     1730         */
     1731        if (ip_address == NULL) {
     1732                return samdb_server_site_name(ldb, mem_ctx);
     1733        }
     1734
     1735        sites_container_dn = samdb_sites_dn(ldb, mem_ctx);
     1736        if (sites_container_dn == NULL) {
     1737                return NULL;
     1738        }
     1739
     1740        subnets_dn = ldb_dn_copy(mem_ctx, sites_container_dn);
     1741        if ( ! ldb_dn_add_child_fmt(subnets_dn, "CN=Subnets")) {
     1742                talloc_free(sites_container_dn);
     1743                talloc_free(subnets_dn);
     1744                return NULL;
     1745        }
     1746
     1747        ret = ldb_search(ldb, mem_ctx, &res, subnets_dn, LDB_SCOPE_ONELEVEL,
     1748                         attrs, NULL);
     1749        if (ret == LDB_ERR_NO_SUCH_OBJECT) {
     1750                count = 0;
     1751        } else if (ret != LDB_SUCCESS) {
     1752                talloc_free(sites_container_dn);
     1753                talloc_free(subnets_dn);
     1754                return NULL;
     1755        } else {
     1756                count = res->count;
     1757        }
     1758
     1759        for (i = 0; i < count; i++) {
     1760                l_subnet_name = ldb_msg_find_attr_as_string(res->msgs[i], "cn",
     1761                                                            NULL);
     1762
     1763                allow_list[0] = l_subnet_name;
     1764
     1765                if (allow_access(mem_ctx, NULL, allow_list, "", ip_address)) {
     1766                        sites_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx,
     1767                                                           res->msgs[i],
     1768                                                           "siteObject");
     1769                        if (sites_dn == NULL) {
     1770                                /* No reference, maybe another subnet matches */
     1771                                continue;
     1772                        }
     1773
     1774                        /* "val" cannot be NULL here since "sites_dn" != NULL */
     1775                        val = ldb_dn_get_rdn_val(sites_dn);
     1776                        site_name = talloc_strdup(mem_ctx,
     1777                                                  (const char *) val->data);
     1778
     1779                        talloc_free(sites_dn);
     1780
     1781                        break;
     1782                }
     1783        }
     1784
     1785        if (site_name == NULL) {
     1786                /* This is the Windows Server fallback rule: when no subnet
     1787                 * exists and we have only one site available then use it (it
     1788                 * is for sure the same as our server site). If more sites do
     1789                 * exist then we don't know which one to use and set the site
     1790                 * name to "". */
     1791                cnt = samdb_search_count(ldb, mem_ctx, sites_container_dn,
     1792                                         "(objectClass=site)");
     1793                if (cnt == 1) {
     1794                        site_name = samdb_server_site_name(ldb, mem_ctx);
     1795                } else {
     1796                        site_name = talloc_strdup(mem_ctx, "");
     1797                }
     1798                l_subnet_name = NULL;
     1799        }
     1800
     1801        if (subnet_name != NULL) {
     1802                *subnet_name = talloc_strdup(mem_ctx, l_subnet_name);
     1803        }
     1804
     1805        talloc_free(sites_container_dn);
     1806        talloc_free(subnets_dn);
     1807        talloc_free(res);
     1808
     1809        return site_name;
    14901810}
    14911811
     
    15091829
    15101830        ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
    1511         if (ret) {
     1831        if (ret != LDB_SUCCESS) {
    15121832                DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n",
    15131833                         ldb_dn_get_linearized(ldb_get_default_basedn(ldb)),
     
    15431863{
    15441864        const char *attrs[] = { "options", NULL };
    1545         int ret, options;
     1865        uint32_t options;
     1866        int ret;
    15461867        struct ldb_result *res;
    15471868        TALLOC_CTX *tmp_ctx;
     
    15551876        /* Query cn=ntds settings,.... */
    15561877        ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
    1557         if (ret) {
     1878        if (ret != LDB_SUCCESS) {
    15581879                talloc_free(tmp_ctx);
    15591880                return false;
     
    15641885        }
    15651886
    1566         options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
     1887        options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
    15671888        talloc_free(tmp_ctx);
    15681889
    15691890        /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
    1570         if (options & 0x000000001) {
     1891        if (options & DS_NTDSDSA_OPT_IS_GC) {
    15711892                return true;
    15721893        }
     
    15811902        struct ldb_dn *sdn = dn;
    15821903        struct ldb_result *res = NULL;
    1583         int ret = 0;
     1904        int ret = LDB_SUCCESS;
    15841905        const char *attrs[] = { NULL };
    15851906
    15861907        local_ctx = talloc_new(mem_ctx);
    1587         if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
     1908        if (local_ctx == NULL) return ldb_oom(ldb);
    15881909
    15891910        while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
    15901911                ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
    1591                                  "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
     1912                                 "(|(objectClass=domain)(objectClass=builtinDomain))");
    15921913                if (ret == LDB_SUCCESS) {
    15931914                        if (res->count == 1) {
     
    16221943
    16231944/*
    1624   set the user password using plaintext, obeying any user or domain
    1625   password restrictions
    1626 
    1627   note that this function doesn't actually store the result in the
    1628   database, it just fills in the "mod" structure with ldb modify
    1629   elements to setup the correct change when samdb_replace() is
    1630   called. This allows the caller to combine the change with other
    1631   changes (as is needed by some of the set user info levels)
    1632 
    1633   The caller should probably have a transaction wrapping this
    1634 */
    1635 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
    1636                             struct ldb_dn *user_dn,
    1637                             struct ldb_dn *domain_dn,
    1638                             struct ldb_message *mod,
     1945 * Performs checks on a user password (plaintext UNIX format - attribute
     1946 * "password"). The remaining parameters have to be extracted from the domain
     1947 * object in the AD.
     1948 *
     1949 * Result codes from "enum samr_ValidationStatus" (consider "samr.idl")
     1950 */
     1951enum samr_ValidationStatus samdb_check_password(const DATA_BLOB *password,
     1952                                                const uint32_t pwdProperties,
     1953                                                const uint32_t minPwdLength)
     1954{
     1955        /* checks if the "minPwdLength" property is satisfied */
     1956        if (minPwdLength > password->length)
     1957                return SAMR_VALIDATION_STATUS_PWD_TOO_SHORT;
     1958
     1959        /* checks the password complexity */
     1960        if (((pwdProperties & DOMAIN_PASSWORD_COMPLEX) != 0)
     1961                        && (password->data != NULL)
     1962                        && (!check_password_quality((const char *) password->data)))
     1963                return SAMR_VALIDATION_STATUS_NOT_COMPLEX_ENOUGH;
     1964
     1965        return SAMR_VALIDATION_STATUS_SUCCESS;
     1966}
     1967
     1968/*
     1969 * Callback for "samdb_set_password" password change
     1970 */
     1971int samdb_set_password_callback(struct ldb_request *req, struct ldb_reply *ares)
     1972{
     1973        int ret;
     1974
     1975        if (!ares) {
     1976                return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
     1977        }
     1978
     1979        if (ares->error != LDB_SUCCESS) {
     1980                ret = ares->error;
     1981                req->context = talloc_steal(req,
     1982                                            ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
     1983                talloc_free(ares);
     1984                return ldb_request_done(req, ret);
     1985        }
     1986
     1987        if (ares->type != LDB_REPLY_DONE) {
     1988                talloc_free(ares);
     1989                return ldb_request_done(req, LDB_ERR_OPERATIONS_ERROR);
     1990        }
     1991
     1992        req->context = talloc_steal(req,
     1993                                    ldb_reply_get_control(ares, DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID));
     1994        talloc_free(ares);
     1995        return ldb_request_done(req, LDB_SUCCESS);
     1996}
     1997
     1998/*
     1999 * Sets the user password using plaintext UTF16 (attribute "new_password") or
     2000 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
     2001 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
     2002 * user change or not. The "rejectReason" gives some more information if the
     2003 * change failed.
     2004 *
     2005 * Results: NT_STATUS_OK, NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
     2006 *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION
     2007 */
     2008NTSTATUS samdb_set_password(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
     2009                            struct ldb_dn *user_dn, struct ldb_dn *domain_dn,
    16392010                            const DATA_BLOB *new_password,
    1640                             struct samr_Password *param_lmNewHash,
    1641                             struct samr_Password *param_ntNewHash,
    1642                             bool user_change,
    1643                             enum samr_RejectReason *reject_reason,
     2011                            const struct samr_Password *lmNewHash,
     2012                            const struct samr_Password *ntNewHash,
     2013                            const struct samr_Password *lmOldHash,
     2014                            const struct samr_Password *ntOldHash,
     2015                            enum samPwdChangeReason *reject_reason,
    16442016                            struct samr_DomInfo1 **_dominfo)
    16452017{
    1646         const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory",
    1647                                             "ntPwdHistory",
    1648                                             "dBCSPwd", "unicodePwd",
    1649                                             "objectSid",
    1650                                             "pwdLastSet", NULL };
    1651         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength",
    1652                                               "maxPwdAge", "minPwdAge",
    1653                                               "minPwdLength", NULL };
    1654         NTTIME pwdLastSet;
    1655         int64_t minPwdAge;
    1656         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
    1657         uint_t userAccountControl;
    1658         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory,
    1659                 *lmPwdHash, *ntPwdHash, *lmNewHash, *ntNewHash;
    1660         struct samr_Password local_lmNewHash, local_ntNewHash;
    1661         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
    1662         struct dom_sid *domain_sid;
    1663         struct ldb_message **res;
    1664         bool restrictions;
    1665         int count;
    1666         time_t now = time(NULL);
    1667         NTTIME now_nt;
    1668         int i;
    1669 
    1670         /* we need to know the time to compute password age */
    1671         unix_to_nt_time(&now_nt, now);
    1672 
    1673         /* pull all the user parameters */
    1674         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
    1675         if (count != 1) {
    1676                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1677         }
    1678         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
    1679         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0],
    1680                                                  "lmPwdHistory", &sambaLMPwdHistory);
    1681         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0],
    1682                                                  "ntPwdHistory", &sambaNTPwdHistory);
    1683         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "dBCSPwd");
    1684         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "unicodePwd");
    1685         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
    1686 
    1687         /* Copy parameters */
    1688         lmNewHash = param_lmNewHash;
    1689         ntNewHash = param_ntNewHash;
    1690 
    1691         /* Only non-trust accounts have restrictions (possibly this
    1692          * test is the wrong way around, but I like to be restrictive
    1693          * if possible */
    1694         restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
    1695                                                |UF_WORKSTATION_TRUST_ACCOUNT
    1696                                                |UF_SERVER_TRUST_ACCOUNT));
    1697 
    1698         if (domain_dn) {
    1699                 /* pull the domain parameters */
    1700                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
    1701                 if (count != 1) {
    1702                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n",
    1703                                   ldb_dn_get_linearized(domain_dn),
    1704                                   ldb_dn_get_linearized(user_dn)));
    1705                         return NT_STATUS_NO_SUCH_DOMAIN;
     2018        struct ldb_message *msg;
     2019        struct ldb_message_element *el;
     2020        struct ldb_request *req;
     2021        struct dsdb_control_password_change_status *pwd_stat = NULL;
     2022        int ret;
     2023        NTSTATUS status = NT_STATUS_OK;
     2024
     2025#define CHECK_RET(x) \
     2026        if (x != LDB_SUCCESS) { \
     2027                talloc_free(msg); \
     2028                return NT_STATUS_NO_MEMORY; \
     2029        }
     2030
     2031        msg = ldb_msg_new(mem_ctx);
     2032        if (msg == NULL) {
     2033                return NT_STATUS_NO_MEMORY;
     2034        }
     2035        msg->dn = user_dn;
     2036        if ((new_password != NULL)
     2037                        && ((lmNewHash == NULL) && (ntNewHash == NULL))) {
     2038                /* we have the password as plaintext UTF16 */
     2039                CHECK_RET(ldb_msg_add_value(msg, "clearTextPassword",
     2040                                            new_password, NULL));
     2041                el = ldb_msg_find_element(msg, "clearTextPassword");
     2042                el->flags = LDB_FLAG_MOD_REPLACE;
     2043        } else if ((new_password == NULL)
     2044                        && ((lmNewHash != NULL) || (ntNewHash != NULL))) {
     2045                /* we have a password as LM and/or NT hash */
     2046                if (lmNewHash != NULL) {
     2047                        CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
     2048                                "dBCSPwd", lmNewHash));
     2049                        el = ldb_msg_find_element(msg, "dBCSPwd");
     2050                        el->flags = LDB_FLAG_MOD_REPLACE;
     2051                }
     2052                if (ntNewHash != NULL) {
     2053                        CHECK_RET(samdb_msg_add_hash(ldb, mem_ctx, msg,
     2054                                "unicodePwd", ntNewHash));
     2055                        el = ldb_msg_find_element(msg, "unicodePwd");
     2056                        el->flags = LDB_FLAG_MOD_REPLACE;
    17062057                }
    17072058        } else {
    1708                 /* work out the domain sid, and pull the domain from there */
    1709                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
    1710                 if (domain_sid == NULL) {
    1711                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
    1712                 }
    1713 
    1714                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs,
    1715                                      "(objectSid=%s)",
    1716                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
    1717                 if (count != 1) {
    1718                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n",
    1719                                   dom_sid_string(mem_ctx, domain_sid),
    1720                                   ldb_dn_get_linearized(user_dn)));
    1721                         return NT_STATUS_NO_SUCH_DOMAIN;
    1722                 }
    1723         }
    1724 
    1725         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
    1726         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
    1727         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
    1728         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
    1729 
    1730         if (userAccountControl & UF_PASSWD_NOTREQD) {
    1731                 /* see [MS-ADTS] 2.2.15 */
    1732                 minPwdLength = 0;
    1733         }
    1734 
    1735         if (_dominfo) {
     2059                /* the password wasn't specified correctly */
     2060                talloc_free(msg);
     2061                return NT_STATUS_INVALID_PARAMETER;
     2062        }
     2063
     2064        /* build modify request */
     2065        ret = ldb_build_mod_req(&req, ldb, mem_ctx, msg, NULL, NULL,
     2066                                samdb_set_password_callback, NULL);
     2067        if (ret != LDB_SUCCESS) {
     2068                talloc_free(msg);
     2069                return NT_STATUS_NO_MEMORY;
     2070        }
     2071
     2072        /* A password change operation */
     2073        if ((ntOldHash != NULL) || (lmOldHash != NULL)) {
     2074                struct dsdb_control_password_change *change;
     2075
     2076                change = talloc(req, struct dsdb_control_password_change);
     2077                if (change == NULL) {
     2078                        talloc_free(req);
     2079                        talloc_free(msg);
     2080                        return NT_STATUS_NO_MEMORY;
     2081                }
     2082
     2083                change->old_nt_pwd_hash = ntOldHash;
     2084                change->old_lm_pwd_hash = lmOldHash;
     2085
     2086                ret = ldb_request_add_control(req,
     2087                                              DSDB_CONTROL_PASSWORD_CHANGE_OID,
     2088                                              true, change);
     2089                if (ret != LDB_SUCCESS) {
     2090                        talloc_free(req);
     2091                        talloc_free(msg);
     2092                        return NT_STATUS_NO_MEMORY;
     2093                }
     2094        }
     2095        ret = ldb_request_add_control(req,
     2096                                      DSDB_CONTROL_PASSWORD_HASH_VALUES_OID,
     2097                                      true, NULL);
     2098        if (ret != LDB_SUCCESS) {
     2099                talloc_free(req);
     2100                talloc_free(msg);
     2101                return NT_STATUS_NO_MEMORY;
     2102        }
     2103        ret = ldb_request_add_control(req,
     2104                                      DSDB_CONTROL_PASSWORD_CHANGE_STATUS_OID,
     2105                                      true, NULL);
     2106        if (ret != LDB_SUCCESS) {
     2107                talloc_free(req);
     2108                talloc_free(msg);
     2109                return NT_STATUS_NO_MEMORY;
     2110        }
     2111
     2112        ret = dsdb_autotransaction_request(ldb, req);
     2113
     2114        if (req->context != NULL) {
     2115                pwd_stat = talloc_steal(mem_ctx,
     2116                                        ((struct ldb_control *)req->context)->data);
     2117        }
     2118
     2119        talloc_free(req);
     2120        talloc_free(msg);
     2121
     2122        /* Sets the domain info (if requested) */
     2123        if (_dominfo != NULL) {
    17362124                struct samr_DomInfo1 *dominfo;
    1737                 /* on failure we need to fill in the reject reasons */
    1738                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
     2125
     2126                dominfo = talloc_zero(mem_ctx, struct samr_DomInfo1);
    17392127                if (dominfo == NULL) {
    17402128                        return NT_STATUS_NO_MEMORY;
    17412129                }
    1742                 dominfo->min_password_length     = minPwdLength;
    1743                 dominfo->password_properties     = pwdProperties;
    1744                 dominfo->password_history_length = pwdHistoryLength;
    1745                 dominfo->max_password_age        = minPwdAge;
    1746                 dominfo->min_password_age        = minPwdAge;
     2130
     2131                if (pwd_stat != NULL) {
     2132                        dominfo->min_password_length     = pwd_stat->domain_data.minPwdLength;
     2133                        dominfo->password_properties     = pwd_stat->domain_data.pwdProperties;
     2134                        dominfo->password_history_length = pwd_stat->domain_data.pwdHistoryLength;
     2135                        dominfo->max_password_age        = pwd_stat->domain_data.maxPwdAge;
     2136                        dominfo->min_password_age        = pwd_stat->domain_data.minPwdAge;
     2137                }
     2138
    17472139                *_dominfo = dominfo;
    17482140        }
    17492141
    1750         if (restrictions && new_password) {
    1751                 char *new_pass;
    1752 
    1753                 /* check the various password restrictions */
    1754                 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
    1755                         if (reject_reason) {
    1756                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
     2142        if (reject_reason != NULL) {
     2143                if (pwd_stat != NULL) {
     2144                        *reject_reason = pwd_stat->reject_reason;
     2145                } else {
     2146                        *reject_reason = SAM_PWD_CHANGE_NO_ERROR;
     2147                }
     2148        }
     2149
     2150        if (pwd_stat != NULL) {
     2151                talloc_free(pwd_stat);
     2152        }
     2153
     2154        if (ret == LDB_ERR_CONSTRAINT_VIOLATION) {
     2155                const char *errmsg = ldb_errstring(ldb);
     2156                char *endptr = NULL;
     2157                WERROR werr = WERR_GENERAL_FAILURE;
     2158                status = NT_STATUS_UNSUCCESSFUL;
     2159                if (errmsg != NULL) {
     2160                        werr = W_ERROR(strtol(errmsg, &endptr, 16));
     2161                }
     2162                if (endptr != errmsg) {
     2163                        if (W_ERROR_EQUAL(werr, WERR_INVALID_PASSWORD)) {
     2164                                status = NT_STATUS_WRONG_PASSWORD;
    17572165                        }
    1758                         return NT_STATUS_PASSWORD_RESTRICTION;
    1759                 }
    1760 
    1761                 /* Create the NT hash */
    1762                 mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
    1763 
    1764                 ntNewHash = &local_ntNewHash;
    1765 
    1766                 /* Only check complexity if we can convert it at all.  Assuming unconvertable passwords are 'strong' */
    1767                 if (convert_string_talloc_convenience(mem_ctx,
    1768                           lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")),
    1769                           CH_UTF16, CH_UNIX,
    1770                           new_password->data, new_password->length,
    1771                           (void **)&new_pass, NULL, false)) {
    1772 
    1773                         /* possibly check password complexity */
    1774                         if (restrictions && (pwdProperties & DOMAIN_PASSWORD_COMPLEX) &&
    1775                             !check_password_quality(new_pass)) {
    1776                                 if (reject_reason) {
    1777                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
    1778                                 }
    1779                                 return NT_STATUS_PASSWORD_RESTRICTION;
     2166                        if (W_ERROR_EQUAL(werr, WERR_PASSWORD_RESTRICTION)) {
     2167                                status = NT_STATUS_PASSWORD_RESTRICTION;
    17802168                        }
    1781 
    1782                         /* compute the new lm hashes (for checking history - case insenitivly!) */
    1783                         if (E_deshash(new_pass, local_lmNewHash.hash)) {
    1784                                 lmNewHash = &local_lmNewHash;
    1785                         }
    1786                 }
    1787         }
    1788 
    1789         if (restrictions && user_change) {
    1790                 /* are all password changes disallowed? */
    1791                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
    1792                         if (reject_reason) {
    1793                                 *reject_reason = SAMR_REJECT_OTHER;
    1794                         }
    1795                         return NT_STATUS_PASSWORD_RESTRICTION;
    1796                 }
    1797 
    1798                 /* can this user change password? */
    1799                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
    1800                         if (reject_reason) {
    1801                                 *reject_reason = SAMR_REJECT_OTHER;
    1802                         }
    1803                         return NT_STATUS_PASSWORD_RESTRICTION;
    1804                 }
    1805 
    1806                 /* yes, this is a minus. The ages are in negative 100nsec units! */
    1807                 if (pwdLastSet - minPwdAge > now_nt) {
    1808                         if (reject_reason) {
    1809                                 *reject_reason = SAMR_REJECT_OTHER;
    1810                         }
    1811                         return NT_STATUS_PASSWORD_RESTRICTION;
    1812                 }
    1813 
    1814                 /* check the immediately past password */
    1815                 if (pwdHistoryLength > 0) {
    1816                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
    1817                                 if (reject_reason) {
    1818                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
    1819                                 }
    1820                                 return NT_STATUS_PASSWORD_RESTRICTION;
    1821                         }
    1822                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
    1823                                 if (reject_reason) {
    1824                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
    1825                                 }
    1826                                 return NT_STATUS_PASSWORD_RESTRICTION;
    1827                         }
    1828                 }
    1829 
    1830                 /* check the password history */
    1831                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
    1832                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
    1833 
    1834                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
    1835                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
    1836                                 if (reject_reason) {
    1837                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
    1838                                 }
    1839                                 return NT_STATUS_PASSWORD_RESTRICTION;
    1840                         }
    1841                 }
    1842                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
    1843                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
    1844                                 if (reject_reason) {
    1845                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
    1846                                 }
    1847                                 return NT_STATUS_PASSWORD_RESTRICTION;
    1848                         }
    1849                 }
    1850         }
    1851 
    1852 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
    1853 
    1854         /* the password is acceptable. Start forming the new fields */
    1855         if (new_password) {
    1856                 /* if we know the cleartext UTF16 password, then set it.
    1857                  * Modules in ldb will set all the appropriate
    1858                  * hashes */
    1859                 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
    1860         } else {
    1861                 /* We don't have the cleartext, so delete the old one
    1862                  * and set what we have of the hashes */
    1863                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
    1864 
    1865                 if (lmNewHash) {
    1866                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
    1867                 } else {
    1868                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
    1869                 }
    1870 
    1871                 if (ntNewHash) {
    1872                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
    1873                 } else {
    1874                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
    1875                 }
    1876         }
    1877 
    1878         return NT_STATUS_OK;
    1879 }
    1880 
    1881 
    1882 /*
    1883   set the user password using plaintext, obeying any user or domain
    1884   password restrictions
    1885 
    1886   This wrapper function takes a SID as input, rather than a user DN,
    1887   and actually performs the password change
    1888 
    1889 */
    1890 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
     2169                }
     2170        } else if (ret == LDB_ERR_NO_SUCH_OBJECT) {
     2171                /* don't let the caller know if an account doesn't exist */
     2172                status = NT_STATUS_WRONG_PASSWORD;
     2173        } else if (ret != LDB_SUCCESS) {
     2174                status = NT_STATUS_UNSUCCESSFUL;
     2175        }
     2176
     2177        return status;
     2178}
     2179
     2180/*
     2181 * Sets the user password using plaintext UTF16 (attribute "new_password") or
     2182 * LM (attribute "lmNewHash") or NT (attribute "ntNewHash") hash. Also pass
     2183 * the old LM and/or NT hash (attributes "lmOldHash"/"ntOldHash") if it is a
     2184 * user change or not. The "rejectReason" gives some more information if the
     2185 * change failed.
     2186 *
     2187 * This wrapper function for "samdb_set_password" takes a SID as input rather
     2188 * than a user DN.
     2189 *
     2190 * This call encapsulates a new LDB transaction for changing the password;
     2191 * therefore the user hasn't to start a new one.
     2192 *
     2193 * Results: NT_STATUS_OK, NT_STATUS_INTERNAL_DB_CORRUPTION,
     2194 *   NT_STATUS_INVALID_PARAMETER, NT_STATUS_UNSUCCESSFUL,
     2195 *   NT_STATUS_WRONG_PASSWORD, NT_STATUS_PASSWORD_RESTRICTION,
     2196 *   NT_STATUS_TRANSACTION_ABORTED, NT_STATUS_NO_SUCH_USER
     2197 */
     2198NTSTATUS samdb_set_password_sid(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    18912199                                const struct dom_sid *user_sid,
    1892                                 const DATA_BLOB *new_pass,
    1893                                 struct samr_Password *lmNewHash,
    1894                                 struct samr_Password *ntNewHash,
    1895                                 bool user_change,
    1896                                 enum samr_RejectReason *reject_reason,
     2200                                const DATA_BLOB *new_password,
     2201                                const struct samr_Password *lmNewHash,
     2202                                const struct samr_Password *ntNewHash,
     2203                                const struct samr_Password *lmOldHash,
     2204                                const struct samr_Password *ntOldHash,
     2205                                enum samPwdChangeReason *reject_reason,
    18972206                                struct samr_DomInfo1 **_dominfo)
    18982207{
    18992208        NTSTATUS nt_status;
    19002209        struct ldb_dn *user_dn;
    1901         struct ldb_message *msg;
    1902         int ret;
    1903 
    1904         ret = ldb_transaction_start(ctx);
    1905         if (ret) {
    1906                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
     2210        int ret;
     2211
     2212        ret = ldb_transaction_start(ldb);
     2213        if (ret != LDB_SUCCESS) {
     2214                DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ldb)));
    19072215                return NT_STATUS_TRANSACTION_ABORTED;
    19082216        }
    19092217
    1910         user_dn = samdb_search_dn(ctx, mem_ctx, NULL,
     2218        user_dn = samdb_search_dn(ldb, mem_ctx, NULL,
    19112219                                  "(&(objectSid=%s)(objectClass=user))",
    19122220                                  ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
    19132221        if (!user_dn) {
    1914                 ldb_transaction_cancel(ctx);
     2222                ldb_transaction_cancel(ldb);
    19152223                DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
    19162224                          dom_sid_string(mem_ctx, user_sid)));
     
    19182226        }
    19192227
    1920         msg = ldb_msg_new(mem_ctx);
    1921         if (msg == NULL) {
    1922                 ldb_transaction_cancel(ctx);
    1923                 return NT_STATUS_NO_MEMORY;
    1924         }
    1925 
    1926         msg->dn = ldb_dn_copy(msg, user_dn);
    1927         if (!msg->dn) {
    1928                 ldb_transaction_cancel(ctx);
    1929                 return NT_STATUS_NO_MEMORY;
    1930         }
    1931 
    1932         nt_status = samdb_set_password(ctx, mem_ctx,
     2228        nt_status = samdb_set_password(ldb, mem_ctx,
    19332229                                       user_dn, NULL,
    1934                                        msg, new_pass,
     2230                                       new_password,
    19352231                                       lmNewHash, ntNewHash,
    1936                                        user_change, /* This is a password set, not change */
     2232                                       lmOldHash, ntOldHash,
    19372233                                       reject_reason, _dominfo);
    19382234        if (!NT_STATUS_IS_OK(nt_status)) {
    1939                 ldb_transaction_cancel(ctx);
     2235                ldb_transaction_cancel(ldb);
     2236                talloc_free(user_dn);
    19402237                return nt_status;
    19412238        }
    19422239
    1943         /* modify the samdb record */
    1944         ret = samdb_replace(ctx, mem_ctx, msg);
    1945         if (ret != 0) {
    1946                 ldb_transaction_cancel(ctx);
    1947                 return NT_STATUS_ACCESS_DENIED;
    1948         }
    1949 
    1950         ret = ldb_transaction_commit(ctx);
    1951         if (ret != 0) {
     2240        ret = ldb_transaction_commit(ldb);
     2241        if (ret != LDB_SUCCESS) {
    19522242                DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
    1953                          ldb_dn_get_linearized(msg->dn),
    1954                          ldb_errstring(ctx)));
     2243                         ldb_dn_get_linearized(user_dn),
     2244                         ldb_errstring(ldb)));
     2245                talloc_free(user_dn);
    19552246                return NT_STATUS_TRANSACTION_ABORTED;
    19562247        }
     2248
     2249        talloc_free(user_dn);
    19572250        return NT_STATUS_OK;
    19582251}
    1959 
    19602252
    19612253
     
    19652257        struct ldb_message *msg;
    19662258        struct ldb_dn *basedn;
    1967         const char *sidstr;
     2259        char *sidstr;
    19682260        int ret;
    19692261
     
    19742266         * is in our own domain */
    19752267
    1976         msg = ldb_msg_new(mem_ctx);
     2268        msg = ldb_msg_new(sidstr);
    19772269        if (msg == NULL) {
     2270                talloc_free(sidstr);
    19782271                return NT_STATUS_NO_MEMORY;
    19792272        }
    19802273
    1981         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
    1982          * put the ForeignSecurityPrincipals? d_state->domain_dn does
    1983          * not work, this is wrong for the Builtin domain, there's no
    1984          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
    1985          */
    1986 
    1987         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
    1988                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
    1989 
    1990         if (basedn == NULL) {
     2274        ret = dsdb_wellknown_dn(sam_ctx, sidstr,
     2275                                ldb_get_default_basedn(sam_ctx),
     2276                                DS_GUID_FOREIGNSECURITYPRINCIPALS_CONTAINER,
     2277                                &basedn);
     2278        if (ret != LDB_SUCCESS) {
    19912279                DEBUG(0, ("Failed to find DN for "
    1992                           "ForeignSecurityPrincipal container\n"));
     2280                          "ForeignSecurityPrincipal container - %s\n", ldb_errstring(sam_ctx)));
     2281                talloc_free(sidstr);
    19932282                return NT_STATUS_INTERNAL_DB_CORRUPTION;
    19942283        }
    19952284
    19962285        /* add core elements to the ldb_message for the alias */
    1997         msg->dn = ldb_dn_copy(mem_ctx, basedn);
    1998         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
     2286        msg->dn = basedn;
     2287        if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr)) {
     2288                talloc_free(sidstr);
    19992289                return NT_STATUS_NO_MEMORY;
    2000 
    2001         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
    2002                              "objectClass",
    2003                              "foreignSecurityPrincipal");
     2290        }
     2291
     2292        ret = ldb_msg_add_string(msg, "objectClass",
     2293                                 "foreignSecurityPrincipal");
     2294        if (ret != LDB_SUCCESS) {
     2295                talloc_free(sidstr);
     2296                return NT_STATUS_NO_MEMORY;
     2297        }
    20042298
    20052299        /* create the alias */
    20062300        ret = ldb_add(sam_ctx, msg);
    2007         if (ret != 0) {
     2301        if (ret != LDB_SUCCESS) {
    20082302                DEBUG(0,("Failed to create foreignSecurityPrincipal "
    20092303                         "record %s: %s\n",
    20102304                         ldb_dn_get_linearized(msg->dn),
    20112305                         ldb_errstring(sam_ctx)));
     2306                talloc_free(sidstr);
    20122307                return NT_STATUS_INTERNAL_DB_CORRUPTION;
    20132308        }
    2014         *ret_dn = msg->dn;
     2309
     2310        *ret_dn = talloc_steal(mem_ctx, msg->dn);
     2311        talloc_free(sidstr);
     2312
    20152313        return NT_STATUS_OK;
    20162314}
     
    20232321struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain)
    20242322{
    2025         int i;
     2323        unsigned int i;
    20262324        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    20272325        const char *binary_encoded;
     
    20512349                DEBUG(2, ("Failed to validated DN %s\n",
    20522350                          ldb_dn_get_linearized(dn)));
     2351                talloc_free(tmp_ctx);
    20532352                return NULL;
    20542353        }
     2354        talloc_free(tmp_ctx);
    20552355        return dn;
    20562356}
     2357
    20572358/*
    20582359  Find the DN of a domain, be it the netbios or DNS name
    20592360*/
    2060 
    20612361struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx,
    20622362                                  const char *domain_name)
     
    20782378                                            "(&(nETBIOSName=%s)(objectclass=crossRef))",
    20792379                                            escaped_domain);
    2080         if (ret_domain != 0) {
     2380        if (ret_domain != LDB_SUCCESS) {
    20812381                return NULL;
    20822382        }
     
    20892389                                                domain_ref2_attrs,
    20902390                                                "(objectclass=domain)");
    2091                 if (ret_domain != 0) {
     2391                if (ret_domain != LDB_SUCCESS) {
    20922392                        return NULL;
    20932393                }
     
    21152415int dsdb_find_dn_by_guid(struct ldb_context *ldb,
    21162416                         TALLOC_CTX *mem_ctx,
    2117                          const char *guid_str, struct ldb_dn **dn)
     2417                         const struct GUID *guid, struct ldb_dn **dn)
    21182418{
    21192419        int ret;
    21202420        struct ldb_result *res;
    21212421        const char *attrs[] = { NULL };
    2122         struct ldb_request *search_req;
    2123         char *expression;
    2124         struct ldb_search_options_control *options;
    2125 
    2126         expression = talloc_asprintf(mem_ctx, "objectGUID=%s", guid_str);
    2127         if (!expression) {
    2128                 DEBUG(0, (__location__ ": out of memory\n"));
    2129                 return LDB_ERR_OPERATIONS_ERROR;
    2130         }
    2131 
    2132         res = talloc_zero(mem_ctx, struct ldb_result);
     2422        char *guid_str = GUID_string(mem_ctx, guid);
     2423
     2424        if (!guid_str) {
     2425                return ldb_operr(ldb);
     2426        }
     2427
     2428        ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
     2429                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
     2430                          DSDB_SEARCH_SHOW_EXTENDED_DN |
     2431                          DSDB_SEARCH_ONE_ONLY,
     2432                          "objectGUID=%s", guid_str);
     2433        talloc_free(guid_str);
     2434        if (ret != LDB_SUCCESS) {
     2435                return ret;
     2436        }
     2437
     2438        *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
     2439        talloc_free(res);
     2440
     2441        return LDB_SUCCESS;
     2442}
     2443
     2444/*
     2445  use a DN to find a GUID with a given attribute name
     2446 */
     2447int dsdb_find_guid_attr_by_dn(struct ldb_context *ldb,
     2448                              struct ldb_dn *dn, const char *attribute,
     2449                              struct GUID *guid)
     2450{
     2451        int ret;
     2452        struct ldb_result *res;
     2453        const char *attrs[2];
     2454        TALLOC_CTX *tmp_ctx = talloc_new(ldb);
     2455
     2456        attrs[0] = attribute;
     2457        attrs[1] = NULL;
     2458
     2459        ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
     2460                             DSDB_SEARCH_SHOW_DELETED |
     2461                             DSDB_SEARCH_SHOW_RECYCLED);
     2462        if (ret != LDB_SUCCESS) {
     2463                talloc_free(tmp_ctx);
     2464                return ret;
     2465        }
     2466        if (res->count < 1) {
     2467                talloc_free(tmp_ctx);
     2468                return LDB_ERR_NO_SUCH_OBJECT;
     2469        }
     2470        *guid = samdb_result_guid(res->msgs[0], attribute);
     2471        talloc_free(tmp_ctx);
     2472        return LDB_SUCCESS;
     2473}
     2474
     2475/*
     2476  use a DN to find a GUID
     2477 */
     2478int dsdb_find_guid_by_dn(struct ldb_context *ldb,
     2479                         struct ldb_dn *dn, struct GUID *guid)
     2480{
     2481        return dsdb_find_guid_attr_by_dn(ldb, dn, "objectGUID", guid);
     2482}
     2483
     2484
     2485
     2486/*
     2487 adds the given GUID to the given ldb_message. This value is added
     2488 for the given attr_name (may be either "objectGUID" or "parentGUID").
     2489 */
     2490int dsdb_msg_add_guid(struct ldb_message *msg,
     2491                struct GUID *guid,
     2492                const char *attr_name)
     2493{
     2494        int ret;
     2495        struct ldb_val v;
     2496        NTSTATUS status;
     2497        TALLOC_CTX *tmp_ctx =  talloc_init("dsdb_msg_add_guid");
     2498
     2499        status = GUID_to_ndr_blob(guid, tmp_ctx, &v);
     2500        if (!NT_STATUS_IS_OK(status)) {
     2501                ret = LDB_ERR_OPERATIONS_ERROR;
     2502                goto done;
     2503        }
     2504
     2505        ret = ldb_msg_add_steal_value(msg, attr_name, &v);
     2506        if (ret != LDB_SUCCESS) {
     2507                DEBUG(4,(__location__ ": Failed to add %s to the message\n",
     2508                                         attr_name));
     2509                goto done;
     2510        }
     2511
     2512        ret = LDB_SUCCESS;
     2513
     2514done:
     2515        talloc_free(tmp_ctx);
     2516        return ret;
     2517
     2518}
     2519
     2520
     2521/*
     2522  use a DN to find a SID
     2523 */
     2524int dsdb_find_sid_by_dn(struct ldb_context *ldb,
     2525                        struct ldb_dn *dn, struct dom_sid *sid)
     2526{
     2527        int ret;
     2528        struct ldb_result *res;
     2529        const char *attrs[] = { "objectSid", NULL };
     2530        TALLOC_CTX *tmp_ctx = talloc_new(ldb);
     2531        struct dom_sid *s;
     2532
     2533        ZERO_STRUCTP(sid);
     2534
     2535        ret = dsdb_search_dn(ldb, tmp_ctx, &res, dn, attrs,
     2536                             DSDB_SEARCH_SHOW_DELETED |
     2537                             DSDB_SEARCH_SHOW_RECYCLED);
     2538        if (ret != LDB_SUCCESS) {
     2539                talloc_free(tmp_ctx);
     2540                return ret;
     2541        }
     2542        if (res->count < 1) {
     2543                talloc_free(tmp_ctx);
     2544                return LDB_ERR_NO_SUCH_OBJECT;
     2545        }
     2546        s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
     2547        if (s == NULL) {
     2548                talloc_free(tmp_ctx);
     2549                return LDB_ERR_NO_SUCH_OBJECT;
     2550        }
     2551        *sid = *s;
     2552        talloc_free(tmp_ctx);
     2553        return LDB_SUCCESS;
     2554}
     2555
     2556/*
     2557  use a SID to find a DN
     2558 */
     2559int dsdb_find_dn_by_sid(struct ldb_context *ldb,
     2560                        TALLOC_CTX *mem_ctx,
     2561                        struct dom_sid *sid, struct ldb_dn **dn)
     2562{
     2563        int ret;
     2564        struct ldb_result *res;
     2565        const char *attrs[] = { NULL };
     2566        char *sid_str = ldap_encode_ndr_dom_sid(mem_ctx, sid);
     2567
     2568        if (!sid_str) {
     2569                return ldb_operr(ldb);
     2570        }
     2571
     2572        ret = dsdb_search(ldb, mem_ctx, &res, NULL, LDB_SCOPE_SUBTREE, attrs,
     2573                          DSDB_SEARCH_SEARCH_ALL_PARTITIONS |
     2574                          DSDB_SEARCH_SHOW_EXTENDED_DN |
     2575                          DSDB_SEARCH_ONE_ONLY,
     2576                          "objectSid=%s", sid_str);
     2577        talloc_free(sid_str);
     2578        if (ret != LDB_SUCCESS) {
     2579                return ret;
     2580        }
     2581
     2582        *dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
     2583        talloc_free(res);
     2584
     2585        return LDB_SUCCESS;
     2586}
     2587
     2588/*
     2589  load a repsFromTo blob list for a given partition GUID
     2590  attr must be "repsFrom" or "repsTo"
     2591 */
     2592WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
     2593                     const char *attr, struct repsFromToBlob **r, uint32_t *count)
     2594{
     2595        const char *attrs[] = { attr, NULL };
     2596        struct ldb_result *res = NULL;
     2597        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     2598        unsigned int i;
     2599        struct ldb_message_element *el;
     2600
     2601        *r = NULL;
     2602        *count = 0;
     2603
     2604        if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
     2605            res->count < 1) {
     2606                DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
     2607                talloc_free(tmp_ctx);
     2608                return WERR_DS_DRA_INTERNAL_ERROR;
     2609        }
     2610
     2611        el = ldb_msg_find_element(res->msgs[0], attr);
     2612        if (el == NULL) {
     2613                /* it's OK to be empty */
     2614                talloc_free(tmp_ctx);
     2615                return WERR_OK;
     2616        }
     2617
     2618        *count = el->num_values;
     2619        *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
     2620        if (*r == NULL) {
     2621                talloc_free(tmp_ctx);
     2622                return WERR_DS_DRA_INTERNAL_ERROR;
     2623        }
     2624
     2625        for (i=0; i<(*count); i++) {
     2626                enum ndr_err_code ndr_err;
     2627                ndr_err = ndr_pull_struct_blob(&el->values[i],
     2628                                               mem_ctx,
     2629                                               &(*r)[i],
     2630                                               (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
     2631                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     2632                        talloc_free(tmp_ctx);
     2633                        return WERR_DS_DRA_INTERNAL_ERROR;
     2634                }
     2635        }
     2636
     2637        talloc_free(tmp_ctx);
     2638       
     2639        return WERR_OK;
     2640}
     2641
     2642/*
     2643  save the repsFromTo blob list for a given partition GUID
     2644  attr must be "repsFrom" or "repsTo"
     2645 */
     2646WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
     2647                     const char *attr, struct repsFromToBlob *r, uint32_t count)
     2648{
     2649        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     2650        struct ldb_message *msg;
     2651        struct ldb_message_element *el;
     2652        unsigned int i;
     2653
     2654        msg = ldb_msg_new(tmp_ctx);
     2655        msg->dn = dn;
     2656        if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
     2657                goto failed;
     2658        }
     2659
     2660        el->values = talloc_array(msg, struct ldb_val, count);
     2661        if (!el->values) {
     2662                goto failed;
     2663        }
     2664
     2665        for (i=0; i<count; i++) {
     2666                struct ldb_val v;
     2667                enum ndr_err_code ndr_err;
     2668
     2669                ndr_err = ndr_push_struct_blob(&v, tmp_ctx,
     2670                                               &r[i],
     2671                                               (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
     2672                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     2673                        goto failed;
     2674                }
     2675
     2676                el->num_values++;
     2677                el->values[i] = v;
     2678        }
     2679
     2680        if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
     2681                DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
     2682                goto failed;
     2683        }
     2684
     2685        talloc_free(tmp_ctx);
     2686       
     2687        return WERR_OK;
     2688
     2689failed:
     2690        talloc_free(tmp_ctx);
     2691        return WERR_DS_DRA_INTERNAL_ERROR;
     2692}
     2693
     2694
     2695/*
     2696  load the uSNHighest and the uSNUrgent attributes from the @REPLCHANGED
     2697  object for a partition
     2698 */
     2699int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn,
     2700                                uint64_t *uSN, uint64_t *urgent_uSN)
     2701{
     2702        struct ldb_request *req;
     2703        int ret;
     2704        TALLOC_CTX *tmp_ctx = talloc_new(ldb);
     2705        struct dsdb_control_current_partition *p_ctrl;
     2706        struct ldb_result *res;
     2707
     2708        res = talloc_zero(tmp_ctx, struct ldb_result);
    21332709        if (!res) {
    2134                 DEBUG(0, (__location__ ": out of memory\n"));
    2135                 return LDB_ERR_OPERATIONS_ERROR;
    2136         }
    2137 
    2138         ret = ldb_build_search_req(&search_req, ldb, mem_ctx,
    2139                                    ldb_get_default_basedn(ldb),
    2140                                    LDB_SCOPE_SUBTREE,
    2141                                    expression, attrs,
     2710                talloc_free(tmp_ctx);
     2711                return ldb_oom(ldb);
     2712        }
     2713
     2714        ret = ldb_build_search_req(&req, ldb, tmp_ctx,
     2715                                   ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
     2716                                   LDB_SCOPE_BASE,
     2717                                   NULL, NULL,
    21422718                                   NULL,
    21432719                                   res, ldb_search_default_callback,
    21442720                                   NULL);
    21452721        if (ret != LDB_SUCCESS) {
     2722                talloc_free(tmp_ctx);
    21462723                return ret;
    21472724        }
    21482725
    2149         /* we need to cope with cross-partition links, so search for
    2150            the GUID over all partitions */
    2151         options = talloc(search_req, struct ldb_search_options_control);
    2152         if (options == NULL) {
    2153                 DEBUG(0, (__location__ ": out of memory\n"));
    2154                 return LDB_ERR_OPERATIONS_ERROR;
    2155         }
    2156         options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
    2157 
    2158         ret = ldb_request_add_control(search_req, LDB_CONTROL_EXTENDED_DN_OID, true, NULL);
    2159         if (ret != LDB_SUCCESS) {
     2726        p_ctrl = talloc(req, struct dsdb_control_current_partition);
     2727        if (p_ctrl == NULL) {
     2728                talloc_free(tmp_ctx);
     2729                return ldb_oom(ldb);
     2730        }
     2731        p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
     2732        p_ctrl->dn = dn;
     2733       
     2734        ret = ldb_request_add_control(req,
     2735                                      DSDB_CONTROL_CURRENT_PARTITION_OID,
     2736                                      false, p_ctrl);
     2737        if (ret != LDB_SUCCESS) {
     2738                talloc_free(tmp_ctx);
    21602739                return ret;
    21612740        }
    2162 
    2163         ret = ldb_request_add_control(search_req,
    2164                                       LDB_CONTROL_SEARCH_OPTIONS_OID,
    2165                                       true, options);
    2166         if (ret != LDB_SUCCESS) {
     2741       
     2742        /* Run the new request */
     2743        ret = ldb_request(ldb, req);
     2744       
     2745        if (ret == LDB_SUCCESS) {
     2746                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     2747        }
     2748
     2749        if (ret == LDB_ERR_NO_SUCH_OBJECT || ret == LDB_ERR_INVALID_DN_SYNTAX) {
     2750                /* it hasn't been created yet, which means
     2751                   an implicit value of zero */
     2752                *uSN = 0;
     2753                talloc_free(tmp_ctx);
     2754                return LDB_SUCCESS;
     2755        }
     2756
     2757        if (ret != LDB_SUCCESS) {
     2758                talloc_free(tmp_ctx);
    21672759                return ret;
    21682760        }
    21692761
    2170         ret = ldb_request(ldb, search_req);
    2171         if (ret != LDB_SUCCESS) {
     2762        if (res->count < 1) {
     2763                *uSN = 0;
     2764                if (urgent_uSN) {
     2765                        *urgent_uSN = 0;
     2766                }
     2767        } else {
     2768                *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
     2769                if (urgent_uSN) {
     2770                        *urgent_uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNUrgent", 0);
     2771                }
     2772        }
     2773
     2774        talloc_free(tmp_ctx);
     2775
     2776        return LDB_SUCCESS;     
     2777}
     2778
     2779int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
     2780                                                   const struct drsuapi_DsReplicaCursor2 *c2)
     2781{
     2782        return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
     2783}
     2784
     2785int drsuapi_DsReplicaCursor_compare(const struct drsuapi_DsReplicaCursor *c1,
     2786                                    const struct drsuapi_DsReplicaCursor *c2)
     2787{
     2788        return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
     2789}
     2790
     2791
     2792/*
     2793  see if a computer identified by its invocationId is a RODC
     2794*/
     2795int samdb_is_rodc(struct ldb_context *sam_ctx, const struct GUID *objectGUID, bool *is_rodc)
     2796{
     2797        /* 1) find the DN for this servers NTDSDSA object
     2798           2) search for the msDS-isRODC attribute
     2799           3) if not present then not a RODC
     2800           4) if present and TRUE then is a RODC
     2801        */
     2802        struct ldb_dn *config_dn;
     2803        const char *attrs[] = { "msDS-isRODC", NULL };
     2804        int ret;
     2805        struct ldb_result *res;
     2806        TALLOC_CTX *tmp_ctx = talloc_new(sam_ctx);
     2807
     2808        config_dn = ldb_get_config_basedn(sam_ctx);
     2809        if (!config_dn) {
     2810                talloc_free(tmp_ctx);
     2811                return ldb_operr(sam_ctx);
     2812        }
     2813
     2814        ret = dsdb_search(sam_ctx, tmp_ctx, &res, config_dn, LDB_SCOPE_SUBTREE, attrs,
     2815                          DSDB_SEARCH_ONE_ONLY, "objectGUID=%s", GUID_string(tmp_ctx, objectGUID));
     2816
     2817        if (ret == LDB_ERR_NO_SUCH_OBJECT) {
     2818                *is_rodc = false;
     2819                talloc_free(tmp_ctx);
     2820                return LDB_SUCCESS;
     2821        }
     2822
     2823        if (ret != LDB_SUCCESS) {
     2824                DEBUG(1,(("Failed to find our own NTDS Settings object by objectGUID=%s!\n"),
     2825                         GUID_string(tmp_ctx, objectGUID)));
     2826                *is_rodc = false;
     2827                talloc_free(tmp_ctx);
    21722828                return ret;
    21732829        }
    21742830
    2175         ret = ldb_wait(search_req->handle, LDB_WAIT_ALL);
     2831        ret = ldb_msg_find_attr_as_bool(res->msgs[0], "msDS-isRODC", 0);
     2832        *is_rodc = (ret == 1);
     2833
     2834        talloc_free(tmp_ctx);
     2835        return LDB_SUCCESS;
     2836}
     2837
     2838
     2839/*
     2840  see if we are a RODC
     2841*/
     2842int samdb_rodc(struct ldb_context *sam_ctx, bool *am_rodc)
     2843{
     2844        const struct GUID *objectGUID;
     2845        int ret;
     2846        bool *cached;
     2847
     2848        /* see if we have a cached copy */
     2849        cached = (bool *)ldb_get_opaque(sam_ctx, "cache.am_rodc");
     2850        if (cached) {
     2851                *am_rodc = *cached;
     2852                return LDB_SUCCESS;
     2853        }
     2854
     2855        objectGUID = samdb_ntds_objectGUID(sam_ctx);
     2856        if (!objectGUID) {
     2857                return ldb_operr(sam_ctx);
     2858        }
     2859
     2860        ret = samdb_is_rodc(sam_ctx, objectGUID, am_rodc);
    21762861        if (ret != LDB_SUCCESS) {
    21772862                return ret;
    21782863        }
    21792864
    2180         /* this really should be exactly 1, but there is a bug in the
    2181            partitions module that can return two here with the
    2182            search_options control set */
    2183         if (res->count < 1) {
     2865        cached = talloc(sam_ctx, bool);
     2866        if (cached == NULL) {
     2867                return ldb_oom(sam_ctx);
     2868        }
     2869        *cached = *am_rodc;
     2870
     2871        ret = ldb_set_opaque(sam_ctx, "cache.am_rodc", cached);
     2872        if (ret != LDB_SUCCESS) {
     2873                talloc_free(cached);
     2874                return ldb_operr(sam_ctx);
     2875        }
     2876
     2877        return LDB_SUCCESS;
     2878}
     2879
     2880bool samdb_set_am_rodc(struct ldb_context *ldb, bool am_rodc)
     2881{
     2882        TALLOC_CTX *tmp_ctx;
     2883        bool *cached;
     2884
     2885        tmp_ctx = talloc_new(ldb);
     2886        if (tmp_ctx == NULL) {
     2887                goto failed;
     2888        }
     2889
     2890        cached = talloc(tmp_ctx, bool);
     2891        if (!cached) {
     2892                goto failed;
     2893        }
     2894
     2895        *cached = am_rodc;
     2896        if (ldb_set_opaque(ldb, "cache.am_rodc", cached) != LDB_SUCCESS) {
     2897                goto failed;
     2898        }
     2899
     2900        talloc_steal(ldb, cached);
     2901        talloc_free(tmp_ctx);
     2902        return true;
     2903
     2904failed:
     2905        DEBUG(1,("Failed to set our own cached am_rodc in the ldb!\n"));
     2906        talloc_free(tmp_ctx);
     2907        return false;
     2908}
     2909
     2910
     2911/*
     2912  return NTDS options flags. See MS-ADTS 7.1.1.2.2.1.2.1.1
     2913
     2914  flags are DS_NTDS_OPTION_*
     2915*/
     2916int samdb_ntds_options(struct ldb_context *ldb, uint32_t *options)
     2917{
     2918        TALLOC_CTX *tmp_ctx;
     2919        const char *attrs[] = { "options", NULL };
     2920        int ret;
     2921        struct ldb_result *res;
     2922
     2923        tmp_ctx = talloc_new(ldb);
     2924        if (tmp_ctx == NULL) {
     2925                goto failed;
     2926        }
     2927
     2928        ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
     2929        if (ret != LDB_SUCCESS) {
     2930                goto failed;
     2931        }
     2932
     2933        if (res->count != 1) {
     2934                goto failed;
     2935        }
     2936
     2937        *options = ldb_msg_find_attr_as_uint(res->msgs[0], "options", 0);
     2938
     2939        talloc_free(tmp_ctx);
     2940
     2941        return LDB_SUCCESS;
     2942
     2943failed:
     2944        DEBUG(1,("Failed to find our own NTDS Settings options in the ldb!\n"));
     2945        talloc_free(tmp_ctx);
     2946        return LDB_ERR_NO_SUCH_OBJECT;
     2947}
     2948
     2949const char* samdb_ntds_object_category(TALLOC_CTX *tmp_ctx, struct ldb_context *ldb)
     2950{
     2951        const char *attrs[] = { "objectCategory", NULL };
     2952        int ret;
     2953        struct ldb_result *res;
     2954
     2955        ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
     2956        if (ret != LDB_SUCCESS) {
     2957                goto failed;
     2958        }
     2959
     2960        if (res->count != 1) {
     2961                goto failed;
     2962        }
     2963
     2964        return ldb_msg_find_attr_as_string(res->msgs[0], "objectCategory", NULL);
     2965
     2966failed:
     2967        DEBUG(1,("Failed to find our own NTDS Settings objectCategory in the ldb!\n"));
     2968        return NULL;
     2969}
     2970
     2971/*
     2972 * Function which generates a "lDAPDisplayName" attribute from a "CN" one.
     2973 * Algorithm implemented according to MS-ADTS 3.1.1.2.3.4
     2974 */
     2975const char *samdb_cn_to_lDAPDisplayName(TALLOC_CTX *mem_ctx, const char *cn)
     2976{
     2977        char **tokens, *ret;
     2978        size_t i;
     2979
     2980        tokens = str_list_make(mem_ctx, cn, " -_");
     2981        if (tokens == NULL)
     2982                return NULL;
     2983
     2984        /* "tolower()" and "toupper()" should also work properly on 0x00 */
     2985        tokens[0][0] = tolower(tokens[0][0]);
     2986        for (i = 1; i < str_list_length((const char **)tokens); i++)
     2987                tokens[i][0] = toupper(tokens[i][0]);
     2988
     2989        ret = talloc_strdup(mem_ctx, tokens[0]);
     2990        for (i = 1; i < str_list_length((const char **)tokens); i++)
     2991                ret = talloc_asprintf_append_buffer(ret, "%s", tokens[i]);
     2992
     2993        talloc_free(tokens);
     2994
     2995        return ret;
     2996}
     2997
     2998/*
     2999 * This detects and returns the domain functional level (DS_DOMAIN_FUNCTION_*)
     3000 */
     3001int dsdb_functional_level(struct ldb_context *ldb)
     3002{
     3003        int *domainFunctionality =
     3004                talloc_get_type(ldb_get_opaque(ldb, "domainFunctionality"), int);
     3005        if (!domainFunctionality) {
     3006                /* this is expected during initial provision */
     3007                DEBUG(4,(__location__ ": WARNING: domainFunctionality not setup\n"));
     3008                return DS_DOMAIN_FUNCTION_2000;
     3009        }
     3010        return *domainFunctionality;
     3011}
     3012
     3013/*
     3014 * This detects and returns the forest functional level (DS_DOMAIN_FUNCTION_*)
     3015 */
     3016int dsdb_forest_functional_level(struct ldb_context *ldb)
     3017{
     3018        int *forestFunctionality =
     3019                talloc_get_type(ldb_get_opaque(ldb, "forestFunctionality"), int);
     3020        if (!forestFunctionality) {
     3021                DEBUG(0,(__location__ ": WARNING: forestFunctionality not setup\n"));
     3022                return DS_DOMAIN_FUNCTION_2000;
     3023        }
     3024        return *forestFunctionality;
     3025}
     3026
     3027/*
     3028  set a GUID in an extended DN structure
     3029 */
     3030int dsdb_set_extended_dn_guid(struct ldb_dn *dn, const struct GUID *guid, const char *component_name)
     3031{
     3032        struct ldb_val v;
     3033        NTSTATUS status;
     3034        int ret;
     3035
     3036        status = GUID_to_ndr_blob(guid, dn, &v);
     3037        if (!NT_STATUS_IS_OK(status)) {
     3038                return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
     3039        }
     3040
     3041        ret = ldb_dn_set_extended_component(dn, component_name, &v);
     3042        data_blob_free(&v);
     3043        return ret;
     3044}
     3045
     3046/*
     3047  return a GUID from a extended DN structure
     3048 */
     3049NTSTATUS dsdb_get_extended_dn_guid(struct ldb_dn *dn, struct GUID *guid, const char *component_name)
     3050{
     3051        const struct ldb_val *v;
     3052
     3053        v = ldb_dn_get_extended_component(dn, component_name);
     3054        if (v == NULL) {
     3055                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     3056        }
     3057
     3058        return GUID_from_ndr_blob(v, guid);
     3059}
     3060
     3061/*
     3062  return a uint64_t from a extended DN structure
     3063 */
     3064NTSTATUS dsdb_get_extended_dn_uint64(struct ldb_dn *dn, uint64_t *val, const char *component_name)
     3065{
     3066        const struct ldb_val *v;
     3067        char *s;
     3068
     3069        v = ldb_dn_get_extended_component(dn, component_name);
     3070        if (v == NULL) {
     3071                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     3072        }
     3073        s = talloc_strndup(dn, (const char *)v->data, v->length);
     3074        NT_STATUS_HAVE_NO_MEMORY(s);
     3075
     3076        *val = strtoull(s, NULL, 0);
     3077
     3078        talloc_free(s);
     3079        return NT_STATUS_OK;
     3080}
     3081
     3082/*
     3083  return a NTTIME from a extended DN structure
     3084 */
     3085NTSTATUS dsdb_get_extended_dn_nttime(struct ldb_dn *dn, NTTIME *nttime, const char *component_name)
     3086{
     3087        return dsdb_get_extended_dn_uint64(dn, nttime, component_name);
     3088}
     3089
     3090/*
     3091  return a uint32_t from a extended DN structure
     3092 */
     3093NTSTATUS dsdb_get_extended_dn_uint32(struct ldb_dn *dn, uint32_t *val, const char *component_name)
     3094{
     3095        const struct ldb_val *v;
     3096        char *s;
     3097
     3098        v = ldb_dn_get_extended_component(dn, component_name);
     3099        if (v == NULL) {
     3100                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     3101        }
     3102
     3103        s = talloc_strndup(dn, (const char *)v->data, v->length);
     3104        NT_STATUS_HAVE_NO_MEMORY(s);
     3105
     3106        *val = strtoul(s, NULL, 0);
     3107
     3108        talloc_free(s);
     3109        return NT_STATUS_OK;
     3110}
     3111
     3112/*
     3113  return a dom_sid from a extended DN structure
     3114 */
     3115NTSTATUS dsdb_get_extended_dn_sid(struct ldb_dn *dn, struct dom_sid *sid, const char *component_name)
     3116{
     3117        const struct ldb_val *sid_blob;
     3118        struct TALLOC_CTX *tmp_ctx;
     3119        enum ndr_err_code ndr_err;
     3120
     3121        sid_blob = ldb_dn_get_extended_component(dn, component_name);
     3122        if (!sid_blob) {
     3123                return NT_STATUS_OBJECT_NAME_NOT_FOUND;
     3124        }
     3125
     3126        tmp_ctx = talloc_new(NULL);
     3127
     3128        ndr_err = ndr_pull_struct_blob_all(sid_blob, tmp_ctx, sid,
     3129                                           (ndr_pull_flags_fn_t)ndr_pull_dom_sid);
     3130        if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     3131                NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
     3132                talloc_free(tmp_ctx);
     3133                return status;
     3134        }
     3135
     3136        talloc_free(tmp_ctx);
     3137        return NT_STATUS_OK;
     3138}
     3139
     3140
     3141/*
     3142  return RMD_FLAGS directly from a ldb_dn
     3143  returns 0 if not found
     3144 */
     3145uint32_t dsdb_dn_rmd_flags(struct ldb_dn *dn)
     3146{
     3147        const struct ldb_val *v;
     3148        char buf[32];
     3149        v = ldb_dn_get_extended_component(dn, "RMD_FLAGS");
     3150        if (!v || v->length > sizeof(buf)-1) return 0;
     3151        strncpy(buf, (const char *)v->data, v->length);
     3152        buf[v->length] = 0;
     3153        return strtoul(buf, NULL, 10);
     3154}
     3155
     3156/*
     3157  return RMD_FLAGS directly from a ldb_val for a DN
     3158  returns 0 if RMD_FLAGS is not found
     3159 */
     3160uint32_t dsdb_dn_val_rmd_flags(const struct ldb_val *val)
     3161{
     3162        const char *p;
     3163        uint32_t flags;
     3164        char *end;
     3165
     3166        if (val->length < 13) {
     3167                return 0;
     3168        }
     3169        p = memmem(val->data, val->length, "<RMD_FLAGS=", 11);
     3170        if (!p) {
     3171                return 0;
     3172        }
     3173        flags = strtoul(p+11, &end, 10);
     3174        if (!end || *end != '>') {
     3175                /* it must end in a > */
     3176                return 0;
     3177        }
     3178        return flags;
     3179}
     3180
     3181/*
     3182  return true if a ldb_val containing a DN in storage form is deleted
     3183 */
     3184bool dsdb_dn_is_deleted_val(const struct ldb_val *val)
     3185{
     3186        return (dsdb_dn_val_rmd_flags(val) & DSDB_RMD_FLAG_DELETED) != 0;
     3187}
     3188
     3189/*
     3190  return true if a ldb_val containing a DN in storage form is
     3191  in the upgraded w2k3 linked attribute format
     3192 */
     3193bool dsdb_dn_is_upgraded_link_val(struct ldb_val *val)
     3194{
     3195        return memmem(val->data, val->length, "<RMD_ADDTIME=", 13) != NULL;
     3196}
     3197
     3198/*
     3199  return a DN for a wellknown GUID
     3200 */
     3201int dsdb_wellknown_dn(struct ldb_context *samdb, TALLOC_CTX *mem_ctx,
     3202                      struct ldb_dn *nc_root, const char *wk_guid,
     3203                      struct ldb_dn **wkguid_dn)
     3204{
     3205        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     3206        const char *attrs[] = { NULL };
     3207        int ret;
     3208        struct ldb_dn *dn;
     3209        struct ldb_result *res;
     3210
     3211        /* construct the magic WKGUID DN */
     3212        dn = ldb_dn_new_fmt(tmp_ctx, samdb, "<WKGUID=%s,%s>",
     3213                            wk_guid, ldb_dn_get_linearized(nc_root));
     3214        if (!wkguid_dn) {
     3215                talloc_free(tmp_ctx);
     3216                return ldb_operr(samdb);
     3217        }
     3218
     3219        ret = dsdb_search_dn(samdb, tmp_ctx, &res, dn, attrs,
     3220                             DSDB_SEARCH_SHOW_DELETED |
     3221                             DSDB_SEARCH_SHOW_RECYCLED);
     3222        if (ret != LDB_SUCCESS) {
     3223                talloc_free(tmp_ctx);
     3224                return ret;
     3225        }
     3226
     3227        (*wkguid_dn) = talloc_steal(mem_ctx, res->msgs[0]->dn);
     3228        talloc_free(tmp_ctx);
     3229        return LDB_SUCCESS;
     3230}
     3231
     3232
     3233static int dsdb_dn_compare_ptrs(struct ldb_dn **dn1, struct ldb_dn **dn2)
     3234{
     3235        return ldb_dn_compare(*dn1, *dn2);
     3236}
     3237
     3238/*
     3239  find a NC root given a DN within the NC
     3240 */
     3241int dsdb_find_nc_root(struct ldb_context *samdb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
     3242                      struct ldb_dn **nc_root)
     3243{
     3244        const char *root_attrs[] = { "namingContexts", NULL };
     3245        TALLOC_CTX *tmp_ctx;
     3246        int ret;
     3247        struct ldb_message_element *el;
     3248        struct ldb_result *root_res;
     3249        unsigned int i;
     3250        struct ldb_dn **nc_dns;
     3251
     3252        tmp_ctx = talloc_new(samdb);
     3253        if (tmp_ctx == NULL) {
     3254                return ldb_oom(samdb);
     3255        }
     3256
     3257        ret = ldb_search(samdb, tmp_ctx, &root_res,
     3258                         ldb_dn_new(tmp_ctx, samdb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
     3259        if (ret != LDB_SUCCESS) {
     3260                DEBUG(1,("Searching for namingContexts in rootDSE failed: %s\n", ldb_errstring(samdb)));
     3261                talloc_free(tmp_ctx);
     3262                return ret;
     3263        }
     3264
     3265        el = ldb_msg_find_element(root_res->msgs[0], "namingContexts");
     3266        if ((el == NULL) || (el->num_values < 3)) {
     3267                struct ldb_message *tmp_msg;
     3268
     3269                DEBUG(5,("dsdb_find_nc_root: Finding a valid 'namingContexts' element in the RootDSE failed. Using a temporary list."));
     3270
     3271                /* This generates a temporary list of NCs in order to let the
     3272                 * provisioning work. */
     3273                tmp_msg = ldb_msg_new(tmp_ctx);
     3274                if (tmp_msg == NULL) {
     3275                        talloc_free(tmp_ctx);
     3276                        return ldb_oom(samdb);
     3277                }
     3278                ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
     3279                                               ldb_dn_alloc_linearized(tmp_msg, ldb_get_schema_basedn(samdb)));
     3280                if (ret != LDB_SUCCESS) {
     3281                        talloc_free(tmp_ctx);
     3282                        return ret;
     3283                }
     3284                ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
     3285                                               ldb_dn_alloc_linearized(tmp_msg, ldb_get_config_basedn(samdb)));
     3286                if (ret != LDB_SUCCESS) {
     3287                        talloc_free(tmp_ctx);
     3288                        return ret;
     3289                }
     3290                ret = ldb_msg_add_steal_string(tmp_msg, "namingContexts",
     3291                                               ldb_dn_alloc_linearized(tmp_msg, ldb_get_default_basedn(samdb)));
     3292                if (ret != LDB_SUCCESS) {
     3293                        talloc_free(tmp_ctx);
     3294                        return ret;
     3295                }
     3296                el = &tmp_msg->elements[0];
     3297        }
     3298
     3299       nc_dns = talloc_array(tmp_ctx, struct ldb_dn *, el->num_values);
     3300       if (!nc_dns) {
     3301               talloc_free(tmp_ctx);
     3302               return ldb_oom(samdb);
     3303       }
     3304
     3305       for (i=0; i<el->num_values; i++) {
     3306               nc_dns[i] = ldb_dn_from_ldb_val(nc_dns, samdb, &el->values[i]);
     3307               if (nc_dns[i] == NULL) {
     3308                       talloc_free(tmp_ctx);
     3309                       return ldb_operr(samdb);
     3310               }
     3311       }
     3312
     3313       TYPESAFE_QSORT(nc_dns, el->num_values, dsdb_dn_compare_ptrs);
     3314
     3315       for (i=0; i<el->num_values; i++) {
     3316               if (ldb_dn_compare_base(nc_dns[i], dn) == 0) {
     3317                       (*nc_root) = talloc_steal(mem_ctx, nc_dns[i]);
     3318                       talloc_free(tmp_ctx);
     3319                       return LDB_SUCCESS;
     3320               }
     3321       }
     3322
     3323       talloc_free(tmp_ctx);
     3324       return LDB_ERR_NO_SUCH_OBJECT;
     3325}
     3326
     3327
     3328/*
     3329  find the deleted objects DN for any object, by looking for the NC
     3330  root, then looking up the wellknown GUID
     3331 */
     3332int dsdb_get_deleted_objects_dn(struct ldb_context *ldb,
     3333                                TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
     3334                                struct ldb_dn **do_dn)
     3335{
     3336        struct ldb_dn *nc_root;
     3337        int ret;
     3338
     3339        ret = dsdb_find_nc_root(ldb, mem_ctx, obj_dn, &nc_root);
     3340        if (ret != LDB_SUCCESS) {
     3341                return ret;
     3342        }
     3343
     3344        ret = dsdb_wellknown_dn(ldb, mem_ctx, nc_root, DS_GUID_DELETED_OBJECTS_CONTAINER, do_dn);
     3345        talloc_free(nc_root);
     3346        return ret;
     3347}
     3348
     3349/*
     3350  return the tombstoneLifetime, in days
     3351 */
     3352int dsdb_tombstone_lifetime(struct ldb_context *ldb, uint32_t *lifetime)
     3353{
     3354        struct ldb_dn *dn;
     3355        dn = ldb_get_config_basedn(ldb);
     3356        if (!dn) {
    21843357                return LDB_ERR_NO_SUCH_OBJECT;
    21853358        }
    2186 
    2187         *dn = res->msgs[0]->dn;
    2188 
     3359        dn = ldb_dn_copy(ldb, dn);
     3360        if (!dn) {
     3361                return ldb_operr(ldb);
     3362        }
     3363        /* see MS-ADTS section 7.1.1.2.4.1.1. There doesn't appear to
     3364         be a wellknown GUID for this */
     3365        if (!ldb_dn_add_child_fmt(dn, "CN=Directory Service,CN=Windows NT,CN=Services")) {
     3366                talloc_free(dn);
     3367                return ldb_operr(ldb);
     3368        }
     3369
     3370        *lifetime = samdb_search_uint(ldb, dn, 180, dn, "tombstoneLifetime", "objectClass=nTDSService");
     3371        talloc_free(dn);
    21893372        return LDB_SUCCESS;
    21903373}
    21913374
    21923375/*
    2193   search for attrs on one DN, allowing for deleted objects
    2194  */
    2195 int dsdb_search_dn_with_deleted(struct ldb_context *ldb,
    2196                                 TALLOC_CTX *mem_ctx,
    2197                                 struct ldb_result **_res,
    2198                                 struct ldb_dn *basedn,
    2199                                 const char * const *attrs)
    2200 {
    2201         int ret;
     3376  compare a ldb_val to a string case insensitively
     3377 */
     3378int samdb_ldb_val_case_cmp(const char *s, struct ldb_val *v)
     3379{
     3380        size_t len = strlen(s);
     3381        int ret;
     3382        if (len > v->length) return 1;
     3383        ret = strncasecmp(s, (const char *)v->data, v->length);
     3384        if (ret != 0) return ret;
     3385        if (v->length > len && v->data[len] != 0) {
     3386                return -1;
     3387        }
     3388        return 0;
     3389}
     3390
     3391
     3392/*
     3393  load the UDV for a partition in v2 format
     3394  The list is returned sorted, and with our local cursor added
     3395 */
     3396int dsdb_load_udv_v2(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
     3397                     struct drsuapi_DsReplicaCursor2 **cursors, uint32_t *count)
     3398{
     3399        static const char *attrs[] = { "replUpToDateVector", NULL };
     3400        struct ldb_result *r;
     3401        const struct ldb_val *ouv_value;
     3402        unsigned int i;
     3403        int ret;
     3404        uint64_t highest_usn;
     3405        const struct GUID *our_invocation_id;
     3406        struct timeval now = timeval_current();
     3407
     3408        ret = ldb_search(samdb, mem_ctx, &r, dn, LDB_SCOPE_BASE, attrs, NULL);
     3409        if (ret != LDB_SUCCESS) {
     3410                return ret;
     3411        }
     3412
     3413        ouv_value = ldb_msg_find_ldb_val(r->msgs[0], "replUpToDateVector");
     3414        if (ouv_value) {
     3415                enum ndr_err_code ndr_err;
     3416                struct replUpToDateVectorBlob ouv;
     3417
     3418                ndr_err = ndr_pull_struct_blob(ouv_value, r, &ouv,
     3419                                               (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
     3420                if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
     3421                        talloc_free(r);
     3422                        return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
     3423                }
     3424                if (ouv.version != 2) {
     3425                        /* we always store as version 2, and
     3426                         * replUpToDateVector is not replicated
     3427                         */
     3428                        return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
     3429                }
     3430
     3431                *count = ouv.ctr.ctr2.count;
     3432                *cursors = talloc_steal(mem_ctx, ouv.ctr.ctr2.cursors);
     3433        } else {
     3434                *count = 0;
     3435                *cursors = NULL;
     3436        }
     3437
     3438        talloc_free(r);
     3439
     3440        our_invocation_id = samdb_ntds_invocation_id(samdb);
     3441        if (!our_invocation_id) {
     3442                DEBUG(0,(__location__ ": No invocationID on samdb - %s\n", ldb_errstring(samdb)));
     3443                talloc_free(*cursors);
     3444                return ldb_operr(samdb);
     3445        }
     3446
     3447        ret = dsdb_load_partition_usn(samdb, dn, &highest_usn, NULL);
     3448        if (ret != LDB_SUCCESS) {
     3449                /* nothing to add - this can happen after a vampire */
     3450                TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
     3451                return LDB_SUCCESS;
     3452        }
     3453
     3454        for (i=0; i<*count; i++) {
     3455                if (GUID_equal(our_invocation_id, &(*cursors)[i].source_dsa_invocation_id)) {
     3456                        (*cursors)[i].highest_usn = highest_usn;
     3457                        (*cursors)[i].last_sync_success = timeval_to_nttime(&now);
     3458                        TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
     3459                        return LDB_SUCCESS;
     3460                }
     3461        }
     3462
     3463        (*cursors) = talloc_realloc(mem_ctx, *cursors, struct drsuapi_DsReplicaCursor2, (*count)+1);
     3464        if (! *cursors) {
     3465                return ldb_oom(samdb);
     3466        }
     3467
     3468        (*cursors)[*count].source_dsa_invocation_id = *our_invocation_id;
     3469        (*cursors)[*count].highest_usn = highest_usn;
     3470        (*cursors)[*count].last_sync_success = timeval_to_nttime(&now);
     3471        (*count)++;
     3472
     3473        TYPESAFE_QSORT(*cursors, *count, drsuapi_DsReplicaCursor2_compare);
     3474
     3475        return LDB_SUCCESS;
     3476}
     3477
     3478/*
     3479  load the UDV for a partition in version 1 format
     3480  The list is returned sorted, and with our local cursor added
     3481 */
     3482int dsdb_load_udv_v1(struct ldb_context *samdb, struct ldb_dn *dn, TALLOC_CTX *mem_ctx,
     3483                     struct drsuapi_DsReplicaCursor **cursors, uint32_t *count)
     3484{
     3485        struct drsuapi_DsReplicaCursor2 *v2;
     3486        uint32_t i;
     3487        int ret;
     3488
     3489        ret = dsdb_load_udv_v2(samdb, dn, mem_ctx, &v2, count);
     3490        if (ret != LDB_SUCCESS) {
     3491                return ret;
     3492        }
     3493
     3494        if (*count == 0) {
     3495                talloc_free(v2);
     3496                *cursors = NULL;
     3497                return LDB_SUCCESS;
     3498        }
     3499
     3500        *cursors = talloc_array(mem_ctx, struct drsuapi_DsReplicaCursor, *count);
     3501        if (*cursors == NULL) {
     3502                talloc_free(v2);
     3503                return ldb_oom(samdb);
     3504        }
     3505
     3506        for (i=0; i<*count; i++) {
     3507                (*cursors)[i].source_dsa_invocation_id = v2[i].source_dsa_invocation_id;
     3508                (*cursors)[i].highest_usn = v2[i].highest_usn;
     3509        }
     3510        talloc_free(v2);
     3511        return LDB_SUCCESS;
     3512}
     3513
     3514/*
     3515  add a set of controls to a ldb_request structure based on a set of
     3516  flags. See util.h for a list of available flags
     3517 */
     3518int dsdb_request_add_controls(struct ldb_request *req, uint32_t dsdb_flags)
     3519{
     3520        int ret;
     3521        if (dsdb_flags & DSDB_SEARCH_SEARCH_ALL_PARTITIONS) {
     3522                struct ldb_search_options_control *options;
     3523                /* Using the phantom root control allows us to search all partitions */
     3524                options = talloc(req, struct ldb_search_options_control);
     3525                if (options == NULL) {
     3526                        return LDB_ERR_OPERATIONS_ERROR;
     3527                }
     3528                options->search_options = LDB_SEARCH_OPTION_PHANTOM_ROOT;
     3529
     3530                ret = ldb_request_add_control(req,
     3531                                              LDB_CONTROL_SEARCH_OPTIONS_OID,
     3532                                              true, options);
     3533                if (ret != LDB_SUCCESS) {
     3534                        return ret;
     3535                }
     3536        }
     3537
     3538        if (dsdb_flags & DSDB_SEARCH_SHOW_DELETED) {
     3539                ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
     3540                if (ret != LDB_SUCCESS) {
     3541                        return ret;
     3542                }
     3543        }
     3544
     3545        if (dsdb_flags & DSDB_SEARCH_SHOW_RECYCLED) {
     3546                ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_RECYCLED_OID, false, NULL);
     3547                if (ret != LDB_SUCCESS) {
     3548                        return ret;
     3549                }
     3550        }
     3551
     3552        if (dsdb_flags & DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT) {
     3553                ret = ldb_request_add_control(req, DSDB_CONTROL_DN_STORAGE_FORMAT_OID, true, NULL);
     3554                if (ret != LDB_SUCCESS) {
     3555                        return ret;
     3556                }
     3557        }
     3558
     3559        if (dsdb_flags & DSDB_SEARCH_SHOW_EXTENDED_DN) {
     3560                struct ldb_extended_dn_control *extended_ctrl = talloc(req, struct ldb_extended_dn_control);
     3561                if (!extended_ctrl) {
     3562                        return LDB_ERR_OPERATIONS_ERROR;
     3563                }
     3564                extended_ctrl->type = 1;
     3565
     3566                ret = ldb_request_add_control(req, LDB_CONTROL_EXTENDED_DN_OID, true, extended_ctrl);
     3567                if (ret != LDB_SUCCESS) {
     3568                        return ret;
     3569                }
     3570        }
     3571
     3572        if (dsdb_flags & DSDB_SEARCH_REVEAL_INTERNALS) {
     3573                ret = ldb_request_add_control(req, LDB_CONTROL_REVEAL_INTERNALS, false, NULL);
     3574                if (ret != LDB_SUCCESS) {
     3575                        return ret;
     3576                }
     3577        }
     3578
     3579        if (dsdb_flags & DSDB_MODIFY_RELAX) {
     3580                ret = ldb_request_add_control(req, LDB_CONTROL_RELAX_OID, false, NULL);
     3581                if (ret != LDB_SUCCESS) {
     3582                        return ret;
     3583                }
     3584        }
     3585
     3586        if (dsdb_flags & DSDB_MODIFY_PERMISSIVE) {
     3587                ret = ldb_request_add_control(req, LDB_CONTROL_PERMISSIVE_MODIFY_OID, false, NULL);
     3588                if (ret != LDB_SUCCESS) {
     3589                        return ret;
     3590                }
     3591        }
     3592
     3593        if (dsdb_flags & DSDB_FLAG_AS_SYSTEM) {
     3594                ret = ldb_request_add_control(req, LDB_CONTROL_AS_SYSTEM_OID, false, NULL);
     3595                if (ret != LDB_SUCCESS) {
     3596                        return ret;
     3597                }
     3598        }
     3599
     3600        if (dsdb_flags & DSDB_TREE_DELETE) {
     3601                ret = ldb_request_add_control(req, LDB_CONTROL_TREE_DELETE_OID, false, NULL);
     3602                if (ret != LDB_SUCCESS) {
     3603                        return ret;
     3604                }
     3605        }
     3606
     3607        if (dsdb_flags & DSDB_PROVISION) {
     3608                ret = ldb_request_add_control(req, LDB_CONTROL_PROVISION_OID, false, NULL);
     3609                if (ret != LDB_SUCCESS) {
     3610                        return ret;
     3611                }
     3612        }
     3613
     3614        return LDB_SUCCESS;
     3615}
     3616
     3617/*
     3618  an add with a set of controls
     3619*/
     3620int dsdb_add(struct ldb_context *ldb, const struct ldb_message *message,
     3621             uint32_t dsdb_flags)
     3622{
    22023623        struct ldb_request *req;
    2203         TALLOC_CTX *tmp_ctx;
     3624        int ret;
     3625
     3626        ret = ldb_build_add_req(&req, ldb, ldb,
     3627                                message,
     3628                                NULL,
     3629                                NULL,
     3630                                ldb_op_default_callback,
     3631                                NULL);
     3632
     3633        if (ret != LDB_SUCCESS) return ret;
     3634
     3635        ret = dsdb_request_add_controls(req, dsdb_flags);
     3636        if (ret != LDB_SUCCESS) {
     3637                talloc_free(req);
     3638                return ret;
     3639        }
     3640
     3641        ret = dsdb_autotransaction_request(ldb, req);
     3642
     3643        talloc_free(req);
     3644        return ret;
     3645}
     3646
     3647/*
     3648  a modify with a set of controls
     3649*/
     3650int dsdb_modify(struct ldb_context *ldb, const struct ldb_message *message,
     3651                uint32_t dsdb_flags)
     3652{
     3653        struct ldb_request *req;
     3654        int ret;
     3655
     3656        ret = ldb_build_mod_req(&req, ldb, ldb,
     3657                                message,
     3658                                NULL,
     3659                                NULL,
     3660                                ldb_op_default_callback,
     3661                                NULL);
     3662
     3663        if (ret != LDB_SUCCESS) return ret;
     3664
     3665        ret = dsdb_request_add_controls(req, dsdb_flags);
     3666        if (ret != LDB_SUCCESS) {
     3667                talloc_free(req);
     3668                return ret;
     3669        }
     3670
     3671        ret = dsdb_autotransaction_request(ldb, req);
     3672
     3673        talloc_free(req);
     3674        return ret;
     3675}
     3676
     3677/*
     3678  like dsdb_modify() but set all the element flags to
     3679  LDB_FLAG_MOD_REPLACE
     3680 */
     3681int dsdb_replace(struct ldb_context *ldb, struct ldb_message *msg, uint32_t dsdb_flags)
     3682{
     3683        unsigned int i;
     3684
     3685        /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
     3686        for (i=0;i<msg->num_elements;i++) {
     3687                msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
     3688        }
     3689
     3690        return dsdb_modify(ldb, msg, dsdb_flags);
     3691}
     3692
     3693
     3694/*
     3695  search for attrs on one DN, allowing for dsdb_flags controls
     3696 */
     3697int dsdb_search_dn(struct ldb_context *ldb,
     3698                   TALLOC_CTX *mem_ctx,
     3699                   struct ldb_result **_res,
     3700                   struct ldb_dn *basedn,
     3701                   const char * const *attrs,
     3702                   uint32_t dsdb_flags)
     3703{
     3704        int ret;
     3705        struct ldb_request *req;
    22043706        struct ldb_result *res;
    22053707
    2206         tmp_ctx = talloc_new(mem_ctx);
    2207 
    2208         res = talloc_zero(tmp_ctx, struct ldb_result);
     3708        res = talloc_zero(mem_ctx, struct ldb_result);
    22093709        if (!res) {
    2210                 return LDB_ERR_OPERATIONS_ERROR;
    2211         }
    2212 
    2213         ret = ldb_build_search_req(&req, ldb, tmp_ctx,
     3710                return ldb_oom(ldb);
     3711        }
     3712
     3713        ret = ldb_build_search_req(&req, ldb, res,
    22143714                                   basedn,
    22153715                                   LDB_SCOPE_BASE,
     
    22213721                                   NULL);
    22223722        if (ret != LDB_SUCCESS) {
    2223                 talloc_free(tmp_ctx);
     3723                talloc_free(res);
    22243724                return ret;
    22253725        }
    22263726
    2227         ret = ldb_request_add_control(req, LDB_CONTROL_SHOW_DELETED_OID, true, NULL);
    2228         if (ret != LDB_SUCCESS) {
     3727        ret = dsdb_request_add_controls(req, dsdb_flags);
     3728        if (ret != LDB_SUCCESS) {
     3729                talloc_free(res);
    22293730                return ret;
    22303731        }
     
    22363737
    22373738        talloc_free(req);
    2238         *_res = talloc_steal(mem_ctx, res);
     3739        if (ret != LDB_SUCCESS) {
     3740                talloc_free(res);
     3741                return ret;
     3742        }
     3743
     3744        *_res = res;
     3745        return LDB_SUCCESS;
     3746}
     3747
     3748/*
     3749  search for attrs on one DN, by the GUID of the DN, allowing for
     3750  dsdb_flags controls
     3751 */
     3752int dsdb_search_by_dn_guid(struct ldb_context *ldb,
     3753                           TALLOC_CTX *mem_ctx,
     3754                           struct ldb_result **_res,
     3755                           const struct GUID *guid,
     3756                           const char * const *attrs,
     3757                           uint32_t dsdb_flags)
     3758{
     3759        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     3760        struct ldb_dn *dn;
     3761        int ret;
     3762
     3763        dn = ldb_dn_new_fmt(tmp_ctx, ldb, "<GUID=%s>", GUID_string(tmp_ctx, guid));
     3764        if (dn == NULL) {
     3765                talloc_free(tmp_ctx);
     3766                return ldb_oom(ldb);
     3767        }
     3768
     3769        ret = dsdb_search_dn(ldb, mem_ctx, _res, dn, attrs, dsdb_flags);
     3770        talloc_free(tmp_ctx);
    22393771        return ret;
    22403772}
    22413773
    2242 
    2243 /*
    2244   use a DN to find a GUID
    2245  */
    2246 int dsdb_find_guid_by_dn(struct ldb_context *ldb,
    2247                          struct ldb_dn *dn, struct GUID *guid)
    2248 {
    2249         int ret;
     3774/*
     3775  general search with dsdb_flags for controls
     3776 */
     3777int dsdb_search(struct ldb_context *ldb,
     3778                TALLOC_CTX *mem_ctx,
     3779                struct ldb_result **_res,
     3780                struct ldb_dn *basedn,
     3781                enum ldb_scope scope,
     3782                const char * const *attrs,
     3783                uint32_t dsdb_flags,
     3784                const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
     3785{
     3786        int ret;
     3787        struct ldb_request *req;
    22503788        struct ldb_result *res;
    2251         const char *attrs[] = { "objectGUID", NULL };
    2252         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    2253 
    2254         ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
    2255         if (ret != LDB_SUCCESS) {
    2256                 talloc_free(tmp_ctx);
    2257                 return ret;
    2258         }
    2259         if (res->count < 1) {
    2260                 talloc_free(tmp_ctx);
    2261                 return LDB_ERR_NO_SUCH_OBJECT;
    2262         }
    2263         *guid = samdb_result_guid(res->msgs[0], "objectGUID");
    2264         talloc_free(tmp_ctx);
    2265         return LDB_SUCCESS;
    2266 }
    2267 
    2268 /*
    2269   use a DN to find a SID
    2270  */
    2271 int dsdb_find_sid_by_dn(struct ldb_context *ldb,
    2272                         struct ldb_dn *dn, struct dom_sid *sid)
    2273 {
    2274         int ret;
    2275         struct ldb_result *res;
    2276         const char *attrs[] = { "objectSID", NULL };
    2277         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    2278         struct dom_sid *s;
    2279 
    2280         ZERO_STRUCTP(sid);
    2281 
    2282         ret = dsdb_search_dn_with_deleted(ldb, tmp_ctx, &res, dn, attrs);
    2283         if (ret != LDB_SUCCESS) {
    2284                 talloc_free(tmp_ctx);
    2285                 return ret;
    2286         }
    2287         if (res->count < 1) {
    2288                 talloc_free(tmp_ctx);
    2289                 return LDB_ERR_NO_SUCH_OBJECT;
    2290         }
    2291         s = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSID");
    2292         if (s == NULL) {
    2293                 talloc_free(tmp_ctx);
    2294                 return LDB_ERR_NO_SUCH_OBJECT;
    2295         }
    2296         *sid = *s;
    2297         talloc_free(tmp_ctx);
    2298         return LDB_SUCCESS;
    2299 }
    2300 
    2301 
    2302 
    2303 /*
    2304   load a repsFromTo blob list for a given partition GUID
    2305   attr must be "repsFrom" or "repsTo"
    2306  */
    2307 WERROR dsdb_loadreps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
    2308                      const char *attr, struct repsFromToBlob **r, uint32_t *count)
    2309 {
    2310         const char *attrs[] = { attr, NULL };
    2311         struct ldb_result *res = NULL;
     3789        va_list ap;
     3790        char *expression = NULL;
    23123791        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    2313         int i;
    2314         struct ldb_message_element *el;
    2315 
    2316         *r = NULL;
    2317         *count = 0;
    2318 
    2319         if (ldb_search(sam_ctx, tmp_ctx, &res, dn, LDB_SCOPE_BASE, attrs, NULL) != LDB_SUCCESS ||
    2320             res->count < 1) {
    2321                 DEBUG(0,("dsdb_loadreps: failed to read partition object\n"));
    2322                 talloc_free(tmp_ctx);
    2323                 return WERR_DS_DRA_INTERNAL_ERROR;
    2324         }
    2325 
    2326         el = ldb_msg_find_element(res->msgs[0], attr);
    2327         if (el == NULL) {
    2328                 /* it's OK to be empty */
    2329                 talloc_free(tmp_ctx);
    2330                 return WERR_OK;
    2331         }
    2332 
    2333         *count = el->num_values;
    2334         *r = talloc_array(mem_ctx, struct repsFromToBlob, *count);
    2335         if (*r == NULL) {
    2336                 talloc_free(tmp_ctx);
    2337                 return WERR_DS_DRA_INTERNAL_ERROR;
    2338         }
    2339 
    2340         for (i=0; i<(*count); i++) {
    2341                 enum ndr_err_code ndr_err;
    2342                 ndr_err = ndr_pull_struct_blob(&el->values[i],
    2343                                                mem_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
    2344                                                &(*r)[i],
    2345                                                (ndr_pull_flags_fn_t)ndr_pull_repsFromToBlob);
    2346                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    2347                         talloc_free(tmp_ctx);
    2348                         return WERR_DS_DRA_INTERNAL_ERROR;
    2349                 }
    2350         }
    2351 
    2352         talloc_free(tmp_ctx);
    2353        
    2354         return WERR_OK;
    2355 }
    2356 
    2357 /*
    2358   save the repsFromTo blob list for a given partition GUID
    2359   attr must be "repsFrom" or "repsTo"
    2360  */
    2361 WERROR dsdb_savereps(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
    2362                      const char *attr, struct repsFromToBlob *r, uint32_t count)
    2363 {
    2364         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
    2365         struct ldb_message *msg;
    2366         struct ldb_message_element *el;
    2367         int i;
    2368 
    2369         msg = ldb_msg_new(tmp_ctx);
    2370         msg->dn = dn;
    2371         if (ldb_msg_add_empty(msg, attr, LDB_FLAG_MOD_REPLACE, &el) != LDB_SUCCESS) {
    2372                 goto failed;
    2373         }
    2374 
    2375         el->values = talloc_array(msg, struct ldb_val, count);
    2376         if (!el->values) {
    2377                 goto failed;
    2378         }
    2379 
    2380         for (i=0; i<count; i++) {
    2381                 struct ldb_val v;
    2382                 enum ndr_err_code ndr_err;
    2383 
    2384                 ndr_err = ndr_push_struct_blob(&v, tmp_ctx, lp_iconv_convenience(ldb_get_opaque(sam_ctx, "loadparm")),
    2385                                                &r[i],
    2386                                                (ndr_push_flags_fn_t)ndr_push_repsFromToBlob);
    2387                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
    2388                         goto failed;
    2389                 }
    2390 
    2391                 el->num_values++;
    2392                 el->values[i] = v;
    2393         }
    2394 
    2395         if (ldb_modify(sam_ctx, msg) != LDB_SUCCESS) {
    2396                 DEBUG(0,("Failed to store %s - %s\n", attr, ldb_errstring(sam_ctx)));
    2397                 goto failed;
    2398         }
    2399 
    2400         talloc_free(tmp_ctx);
    2401        
    2402         return WERR_OK;
    2403 
    2404 failed:
    2405         talloc_free(tmp_ctx);
    2406         return WERR_DS_DRA_INTERNAL_ERROR;
    2407 }
    2408 
    2409 
    2410 /*
    2411   load the uSNHighest attribute from the @REPLCHANGED object for a
    2412   partition
    2413  */
    2414 int dsdb_load_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t *uSN)
    2415 {
    2416         struct ldb_request *req;
    2417         int ret;
    2418         TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    2419         struct dsdb_control_current_partition *p_ctrl;
    2420         struct ldb_result *res;
    24213792
    24223793        res = talloc_zero(tmp_ctx, struct ldb_result);
    24233794        if (!res) {
    24243795                talloc_free(tmp_ctx);
    2425                 return LDB_ERR_OPERATIONS_ERROR;
     3796                return ldb_oom(ldb);
     3797        }
     3798
     3799        if (exp_fmt) {
     3800                va_start(ap, exp_fmt);
     3801                expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
     3802                va_end(ap);
     3803
     3804                if (!expression) {
     3805                        talloc_free(tmp_ctx);
     3806                        return ldb_oom(ldb);
     3807                }
    24263808        }
    24273809
    24283810        ret = ldb_build_search_req(&req, ldb, tmp_ctx,
    2429                                    ldb_dn_new(tmp_ctx, ldb, "@REPLCHANGED"),
    2430                                    LDB_SCOPE_BASE,
    2431                                    NULL, NULL,
     3811                                   basedn,
     3812                                   scope,
     3813                                   expression,
     3814                                   attrs,
    24323815                                   NULL,
    2433                                    res, ldb_search_default_callback,
     3816                                   res,
     3817                                   ldb_search_default_callback,
    24343818                                   NULL);
    24353819        if (ret != LDB_SUCCESS) {
     
    24383822        }
    24393823
    2440         p_ctrl = talloc(req, struct dsdb_control_current_partition);
    2441         if (p_ctrl == NULL) {
    2442                 talloc_free(res);
    2443                 return LDB_ERR_OPERATIONS_ERROR;
    2444         }
    2445         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
    2446         p_ctrl->dn = dn;
    2447        
    2448 
    2449         ret = ldb_request_add_control(req,
    2450                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
    2451                                       false, p_ctrl);
     3824        ret = dsdb_request_add_controls(req, dsdb_flags);
     3825        if (ret != LDB_SUCCESS) {
     3826                talloc_free(tmp_ctx);
     3827                ldb_reset_err_string(ldb);
     3828                return ret;
     3829        }
     3830
     3831        ret = ldb_request(ldb, req);
     3832        if (ret == LDB_SUCCESS) {
     3833                ret = ldb_wait(req->handle, LDB_WAIT_ALL);
     3834        }
     3835
    24523836        if (ret != LDB_SUCCESS) {
    24533837                talloc_free(tmp_ctx);
    24543838                return ret;
    24553839        }
    2456        
    2457         /* Run the new request */
    2458         ret = ldb_request(ldb, req);
    2459        
    2460         if (ret == LDB_SUCCESS) {
    2461                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    2462         }
    2463 
    2464         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    2465                 /* it hasn't been created yet, which means
    2466                    an implicit value of zero */
    2467                 *uSN = 0;
     3840
     3841        if (dsdb_flags & DSDB_SEARCH_ONE_ONLY) {
     3842                if (res->count == 0) {
     3843                        talloc_free(tmp_ctx);
     3844                        ldb_reset_err_string(ldb);
     3845                        return LDB_ERR_NO_SUCH_OBJECT;
     3846                }
     3847                if (res->count != 1) {
     3848                        talloc_free(tmp_ctx);
     3849                        ldb_reset_err_string(ldb);
     3850                        return LDB_ERR_CONSTRAINT_VIOLATION;
     3851                }
     3852        }
     3853
     3854        *_res = talloc_steal(mem_ctx, res);
     3855        talloc_free(tmp_ctx);
     3856
     3857        return LDB_SUCCESS;
     3858}
     3859
     3860
     3861/*
     3862  general search with dsdb_flags for controls
     3863  returns exactly 1 record or an error
     3864 */
     3865int dsdb_search_one(struct ldb_context *ldb,
     3866                    TALLOC_CTX *mem_ctx,
     3867                    struct ldb_message **msg,
     3868                    struct ldb_dn *basedn,
     3869                    enum ldb_scope scope,
     3870                    const char * const *attrs,
     3871                    uint32_t dsdb_flags,
     3872                    const char *exp_fmt, ...) _PRINTF_ATTRIBUTE(8, 9)
     3873{
     3874        int ret;
     3875        struct ldb_result *res;
     3876        va_list ap;
     3877        char *expression = NULL;
     3878        TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
     3879
     3880        dsdb_flags |= DSDB_SEARCH_ONE_ONLY;
     3881
     3882        res = talloc_zero(tmp_ctx, struct ldb_result);
     3883        if (!res) {
    24683884                talloc_free(tmp_ctx);
    2469                 return LDB_SUCCESS;
     3885                return ldb_oom(ldb);
     3886        }
     3887
     3888        if (exp_fmt) {
     3889                va_start(ap, exp_fmt);
     3890                expression = talloc_vasprintf(tmp_ctx, exp_fmt, ap);
     3891                va_end(ap);
     3892
     3893                if (!expression) {
     3894                        talloc_free(tmp_ctx);
     3895                        return ldb_oom(ldb);
     3896                }
     3897                ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
     3898                                  dsdb_flags, "%s", expression);
     3899        } else {
     3900                ret = dsdb_search(ldb, tmp_ctx, &res, basedn, scope, attrs,
     3901                                  dsdb_flags, NULL);
    24703902        }
    24713903
     
    24753907        }
    24763908
    2477         if (res->count < 1) {
    2478                 *uSN = 0;
    2479         } else {
    2480                 *uSN = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNHighest", 0);
    2481         }
    2482 
     3909        *msg = talloc_steal(mem_ctx, res->msgs[0]);
    24833910        talloc_free(tmp_ctx);
    24843911
    2485         return LDB_SUCCESS;     
    2486 }
    2487 
    2488 /*
    2489   save the uSNHighest attribute in the @REPLCHANGED object for a
    2490   partition
    2491  */
    2492 int dsdb_save_partition_usn(struct ldb_context *ldb, struct ldb_dn *dn, uint64_t uSN)
    2493 {
    2494         struct ldb_request *req;
     3912        return LDB_SUCCESS;
     3913}
     3914
     3915/* returns back the forest DNS name */
     3916const char *samdb_forest_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
     3917{
     3918        const char *forest_name = ldb_dn_canonical_string(mem_ctx,
     3919                                                          ldb_get_root_basedn(ldb));
     3920        char *p;
     3921
     3922        if (forest_name == NULL) {
     3923                return NULL;
     3924        }
     3925
     3926        p = strchr(forest_name, '/');
     3927        if (p) {
     3928                *p = '\0';
     3929        }
     3930
     3931        return forest_name;
     3932}
     3933
     3934/* returns back the default domain DNS name */
     3935const char *samdb_default_domain_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
     3936{
     3937        const char *domain_name = ldb_dn_canonical_string(mem_ctx,
     3938                                                          ldb_get_default_basedn(ldb));
     3939        char *p;
     3940
     3941        if (domain_name == NULL) {
     3942                return NULL;
     3943        }
     3944
     3945        p = strchr(domain_name, '/');
     3946        if (p) {
     3947                *p = '\0';
     3948        }
     3949
     3950        return domain_name;
     3951}
     3952
     3953/*
     3954   validate that an DSA GUID belongs to the specified user sid.
     3955   The user SID must be a domain controller account (either RODC or
     3956   RWDC)
     3957 */
     3958int dsdb_validate_dsa_guid(struct ldb_context *ldb,
     3959                           const struct GUID *dsa_guid,
     3960                           const struct dom_sid *sid)
     3961{
     3962        /* strategy:
     3963            - find DN of record with the DSA GUID in the
     3964              configuration partition (objectGUID)
     3965            - remove "NTDS Settings" component from DN
     3966            - do a base search on that DN for serverReference with
     3967              extended-dn enabled
     3968            - extract objectSid from resulting serverReference
     3969              attribute
     3970            - check this sid matches the sid argument
     3971        */
     3972        struct ldb_dn *config_dn;
     3973        TALLOC_CTX *tmp_ctx = talloc_new(ldb);
    24953974        struct ldb_message *msg;
    2496         struct dsdb_control_current_partition *p_ctrl;
    2497         int ret;
    2498 
    2499         msg = ldb_msg_new(ldb);
    2500         if (msg == NULL) {
    2501                 return LDB_ERR_OPERATIONS_ERROR;
    2502         }
    2503 
    2504         msg->dn = ldb_dn_new(msg, ldb, "@REPLCHANGED");
    2505         if (msg->dn == NULL) {
    2506                 talloc_free(msg);
    2507                 return LDB_ERR_OPERATIONS_ERROR;
    2508         }
    2509        
    2510         ret = ldb_msg_add_fmt(msg, "uSNHighest", "%llu", (unsigned long long)uSN);
    2511         if (ret != LDB_SUCCESS) {
    2512                 talloc_free(msg);
    2513                 return ret;
    2514         }
    2515         msg->elements[0].flags = LDB_FLAG_MOD_REPLACE;
    2516        
    2517 
    2518         p_ctrl = talloc(msg, struct dsdb_control_current_partition);
    2519         if (p_ctrl == NULL) {
    2520                 talloc_free(msg);
    2521                 return LDB_ERR_OPERATIONS_ERROR;
    2522         }
    2523         p_ctrl->version = DSDB_CONTROL_CURRENT_PARTITION_VERSION;
    2524         p_ctrl->dn = dn;
    2525 
    2526         ret = ldb_build_mod_req(&req, ldb, msg,
    2527                                 msg,
    2528                                 NULL,
    2529                                 NULL, ldb_op_default_callback,
    2530                                 NULL);
    2531 again:
    2532         if (ret != LDB_SUCCESS) {
    2533                 talloc_free(msg);
    2534                 return ret;
    2535         }
    2536        
    2537         ret = ldb_request_add_control(req,
    2538                                       DSDB_CONTROL_CURRENT_PARTITION_OID,
    2539                                       false, p_ctrl);
    2540         if (ret != LDB_SUCCESS) {
    2541                 talloc_free(msg);
    2542                 return ret;
    2543         }
    2544        
    2545         /* Run the new request */
    2546         ret = ldb_request(ldb, req);
    2547        
    2548         if (ret == LDB_SUCCESS) {
    2549                 ret = ldb_wait(req->handle, LDB_WAIT_ALL);
    2550         }
    2551         if (ret == LDB_ERR_NO_SUCH_OBJECT) {
    2552                 ret = ldb_build_add_req(&req, ldb, msg,
    2553                                         msg,
    2554                                         NULL,
    2555                                         NULL, ldb_op_default_callback,
    2556                                         NULL);
    2557                 goto again;
    2558         }
    2559        
    2560         talloc_free(msg);
    2561        
    2562         return ret;
    2563 }
    2564 
    2565 int drsuapi_DsReplicaCursor2_compare(const struct drsuapi_DsReplicaCursor2 *c1,
    2566                                                    const struct drsuapi_DsReplicaCursor2 *c2)
    2567 {
    2568         return GUID_compare(&c1->source_dsa_invocation_id, &c2->source_dsa_invocation_id);
    2569 }
     3975        const char *attrs1[] = { NULL };
     3976        const char *attrs2[] = { "serverReference", NULL };
     3977        int ret;
     3978        struct ldb_dn *dn, *account_dn;
     3979        struct dom_sid sid2;
     3980        NTSTATUS status;
     3981
     3982        config_dn = ldb_get_config_basedn(ldb);
     3983
     3984        ret = dsdb_search_one(ldb, tmp_ctx, &msg, config_dn, LDB_SCOPE_SUBTREE,
     3985                              attrs1, 0, "(&(objectGUID=%s)(objectClass=nTDSDSA))", GUID_string(tmp_ctx, dsa_guid));
     3986        if (ret != LDB_SUCCESS) {
     3987                DEBUG(1,(__location__ ": Failed to find DSA objectGUID %s for sid %s\n",
     3988                         GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
     3989                talloc_free(tmp_ctx);
     3990                return ldb_operr(ldb);
     3991        }
     3992        dn = msg->dn;
     3993
     3994        if (!ldb_dn_remove_child_components(dn, 1)) {
     3995                talloc_free(tmp_ctx);
     3996                return ldb_operr(ldb);
     3997        }
     3998
     3999        ret = dsdb_search_one(ldb, tmp_ctx, &msg, dn, LDB_SCOPE_BASE,
     4000                              attrs2, DSDB_SEARCH_SHOW_EXTENDED_DN,
     4001                              "(objectClass=server)");
     4002        if (ret != LDB_SUCCESS) {
     4003                DEBUG(1,(__location__ ": Failed to find server record for DSA with objectGUID %s, sid %s\n",
     4004                         GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
     4005                talloc_free(tmp_ctx);
     4006                return ldb_operr(ldb);
     4007        }
     4008
     4009        account_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, msg, "serverReference");
     4010        if (account_dn == NULL) {
     4011                DEBUG(1,(__location__ ": Failed to find account_dn for DSA with objectGUID %s, sid %s\n",
     4012                         GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
     4013                talloc_free(tmp_ctx);
     4014                return ldb_operr(ldb);
     4015        }
     4016
     4017        status = dsdb_get_extended_dn_sid(account_dn, &sid2, "SID");
     4018        if (!NT_STATUS_IS_OK(status)) {
     4019                DEBUG(1,(__location__ ": Failed to find SID for DSA with objectGUID %s, sid %s\n",
     4020                         GUID_string(tmp_ctx, dsa_guid), dom_sid_string(tmp_ctx, sid)));
     4021                talloc_free(tmp_ctx);
     4022                return ldb_operr(ldb);
     4023        }
     4024
     4025        if (!dom_sid_equal(sid, &sid2)) {
     4026                /* someone is trying to spoof another account */
     4027                DEBUG(0,(__location__ ": Bad DSA objectGUID %s for sid %s - expected sid %s\n",
     4028                         GUID_string(tmp_ctx, dsa_guid),
     4029                         dom_sid_string(tmp_ctx, sid),
     4030                         dom_sid_string(tmp_ctx, &sid2)));
     4031                talloc_free(tmp_ctx);
     4032                return ldb_operr(ldb);
     4033        }
     4034
     4035        talloc_free(tmp_ctx);
     4036        return LDB_SUCCESS;
     4037}
     4038
     4039static const char * const secret_attributes[] = {
     4040        DSDB_SECRET_ATTRIBUTES,
     4041        NULL
     4042};
     4043
     4044/*
     4045  check if the attribute belongs to the RODC filtered attribute set
     4046  Note that attributes that are in the filtered attribute set are the
     4047  ones that _are_ always sent to a RODC
     4048*/
     4049bool dsdb_attr_in_rodc_fas(const struct dsdb_attribute *sa)
     4050{
     4051        /* they never get secret attributes */
     4052        if (is_attr_in_list(secret_attributes, sa->lDAPDisplayName)) {
     4053                return false;
     4054        }
     4055
     4056        /* they do get non-secret critical attributes */
     4057        if (sa->schemaFlagsEx & SCHEMA_FLAG_ATTR_IS_CRITICAL) {
     4058                return true;
     4059        }
     4060
     4061        /* they do get non-secret attributes marked as being in the FAS  */
     4062        if (sa->searchFlags & SEARCH_FLAG_RODC_ATTRIBUTE) {
     4063                return true;
     4064        }
     4065
     4066        /* other attributes are denied */
     4067        return false;
     4068}
     4069
     4070/* return fsmo role dn and role owner dn for a particular role*/
     4071WERROR dsdb_get_fsmo_role_info(TALLOC_CTX *tmp_ctx,
     4072                               struct ldb_context *ldb,
     4073                               uint32_t role,
     4074                               struct ldb_dn **fsmo_role_dn,
     4075                               struct ldb_dn **role_owner_dn)
     4076{
     4077        int ret;
     4078        switch (role) {
     4079        case DREPL_NAMING_MASTER:
     4080                *fsmo_role_dn = samdb_partitions_dn(ldb, tmp_ctx);
     4081                ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
     4082                if (ret != LDB_SUCCESS) {
     4083                        DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Naming Master object - %s",
     4084                                 ldb_errstring(ldb)));
     4085                        talloc_free(tmp_ctx);
     4086                        return WERR_DS_DRA_INTERNAL_ERROR;
     4087                }
     4088                break;
     4089        case DREPL_INFRASTRUCTURE_MASTER:
     4090                *fsmo_role_dn = samdb_infrastructure_dn(ldb, tmp_ctx);
     4091                ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
     4092                if (ret != LDB_SUCCESS) {
     4093                        DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
     4094                                 ldb_errstring(ldb)));
     4095                        talloc_free(tmp_ctx);
     4096                        return WERR_DS_DRA_INTERNAL_ERROR;
     4097                }
     4098                break;
     4099        case DREPL_RID_MASTER:
     4100                ret = samdb_rid_manager_dn(ldb, tmp_ctx, fsmo_role_dn);
     4101                if (ret != LDB_SUCCESS) {
     4102                        DEBUG(0, (__location__ ": Failed to find RID Manager object - %s", ldb_errstring(ldb)));
     4103                        talloc_free(tmp_ctx);
     4104                        return WERR_DS_DRA_INTERNAL_ERROR;
     4105                }
     4106
     4107                ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
     4108                if (ret != LDB_SUCCESS) {
     4109                        DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in RID Manager object - %s",
     4110                                 ldb_errstring(ldb)));
     4111                        talloc_free(tmp_ctx);
     4112                        return WERR_DS_DRA_INTERNAL_ERROR;
     4113                }
     4114                break;
     4115        case DREPL_SCHEMA_MASTER:
     4116                *fsmo_role_dn = ldb_get_schema_basedn(ldb);
     4117                ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
     4118                if (ret != LDB_SUCCESS) {
     4119                        DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Schema Master object - %s",
     4120                                 ldb_errstring(ldb)));
     4121                        talloc_free(tmp_ctx);
     4122                        return WERR_DS_DRA_INTERNAL_ERROR;
     4123                }
     4124                break;
     4125        case DREPL_PDC_MASTER:
     4126                *fsmo_role_dn = ldb_get_default_basedn(ldb);
     4127                ret = samdb_reference_dn(ldb, tmp_ctx, *fsmo_role_dn, "fSMORoleOwner", role_owner_dn);
     4128                if (ret != LDB_SUCCESS) {
     4129                        DEBUG(0,(__location__ ": Failed to find fSMORoleOwner in Pd Master object - %s",
     4130                                 ldb_errstring(ldb)));
     4131                        talloc_free(tmp_ctx);
     4132                        return WERR_DS_DRA_INTERNAL_ERROR;
     4133                }
     4134                break;
     4135        default:
     4136                return WERR_DS_DRA_INTERNAL_ERROR;
     4137        }
     4138        return WERR_OK;
     4139}
     4140
     4141const char *samdb_dn_to_dnshostname(struct ldb_context *ldb,
     4142                                    TALLOC_CTX *mem_ctx,
     4143                                    struct ldb_dn *server_dn)
     4144{
     4145        int ldb_ret;
     4146        struct ldb_result *res = NULL;
     4147        const char * const attrs[] = { "dNSHostName", NULL};
     4148
     4149        ldb_ret = ldb_search(ldb, mem_ctx, &res,
     4150                             server_dn,
     4151                             LDB_SCOPE_BASE,
     4152                             attrs, NULL);
     4153        if (ldb_ret != LDB_SUCCESS) {
     4154                DEBUG(4, ("Failed to find dNSHostName for dn %s, ldb error: %s",
     4155                          ldb_dn_get_linearized(server_dn), ldb_errstring(ldb)));
     4156                return NULL;
     4157        }
     4158
     4159        return ldb_msg_find_attr_as_string(res->msgs[0], "dNSHostName", NULL);
     4160}
     4161
     4162/*
     4163  returns true if an attribute is in the filter,
     4164  false otherwise, provided that attribute value is provided with the expression
     4165*/
     4166bool dsdb_attr_in_parse_tree(struct ldb_parse_tree *tree,
     4167                             const char *attr)
     4168{
     4169       unsigned int i;
     4170       switch (tree->operation) {
     4171       case LDB_OP_AND:
     4172       case LDB_OP_OR:
     4173               for (i=0;i<tree->u.list.num_elements;i++) {
     4174                       if (dsdb_attr_in_parse_tree(tree->u.list.elements[i],
     4175                                                       attr))
     4176                               return true;
     4177               }
     4178               return false;
     4179       case LDB_OP_NOT:
     4180               return dsdb_attr_in_parse_tree(tree->u.isnot.child, attr);
     4181       case LDB_OP_EQUALITY:
     4182       case LDB_OP_GREATER:
     4183       case LDB_OP_LESS:
     4184       case LDB_OP_APPROX:
     4185               if (ldb_attr_cmp(tree->u.equality.attr, attr) == 0) {
     4186                       return true;
     4187               }
     4188               return false;
     4189       case LDB_OP_SUBSTRING:
     4190               if (ldb_attr_cmp(tree->u.substring.attr, attr) == 0) {
     4191                       return true;
     4192               }
     4193               return false;
     4194       case LDB_OP_PRESENT:
     4195               /* (attrname=*) is not filtered out */
     4196               return false;
     4197       case LDB_OP_EXTENDED:
     4198               if (tree->u.extended.attr &&
     4199                   ldb_attr_cmp(tree->u.extended.attr, attr) == 0) {
     4200                       return true;
     4201               }
     4202               return false;
     4203       }
     4204       return false;
     4205}
     4206
     4207bool is_attr_in_list(const char * const * attrs, const char *attr)
     4208{
     4209        unsigned int i;
     4210
     4211        for (i = 0; attrs[i]; i++) {
     4212                if (ldb_attr_cmp(attrs[i], attr) == 0)
     4213                        return true;
     4214        }
     4215
     4216        return false;
     4217}
     4218
Note: See TracChangeset for help on using the changeset viewer.