root/source4/dsdb/common/util.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. samdb_search_domain
  2. samdb_search_string_v
  3. samdb_search_string
  4. samdb_search_dn
  5. samdb_search_dom_sid
  6. samdb_search_count
  7. samdb_search_uint
  8. samdb_search_int64
  9. samdb_search_string_multiple
  10. samdb_result_uint
  11. samdb_result_int64
  12. samdb_result_string
  13. samdb_result_dn
  14. samdb_result_rid_from_sid
  15. samdb_result_dom_sid
  16. samdb_result_guid
  17. samdb_result_sid_prefix
  18. samdb_result_nttime
  19. samdb_result_account_expires
  20. samdb_result_uint64
  21. samdb_result_allow_password_change
  22. samdb_result_force_password_change
  23. samdb_result_hash
  24. samdb_result_hashes
  25. samdb_result_passwords
  26. samdb_result_logon_hours
  27. samdb_result_acct_flags
  28. samdb_result_parameters
  29. samdb_find_attribute
  30. samdb_find_or_add_value
  31. samdb_find_or_add_attribute
  32. samdb_msg_add_string
  33. samdb_msg_add_dom_sid
  34. samdb_msg_add_delete
  35. samdb_msg_add_addval
  36. samdb_msg_add_delval
  37. samdb_msg_add_int
  38. samdb_msg_add_uint
  39. samdb_msg_add_int64
  40. samdb_msg_add_uint64
  41. samdb_msg_add_hash
  42. samdb_msg_add_hashes
  43. samdb_msg_add_acct_flags
  44. samdb_msg_add_logon_hours
  45. samdb_msg_add_parameters
  46. samdb_msg_add_value
  47. samdb_msg_set_value
  48. samdb_msg_set_string
  49. samdb_replace
  50. samdb_default_security_descriptor
  51. samdb_base_dn
  52. samdb_config_dn
  53. samdb_schema_dn
  54. samdb_root_dn
  55. samdb_partitions_dn
  56. samdb_sites_dn
  57. samdb_domain_sid
  58. samdb_set_domain_sid
  59. samdb_result_fsmo_name
  60. samdb_ntds_settings_dn
  61. samdb_ntds_invocation_id
  62. samdb_set_ntds_invocation_id
  63. samdb_ntds_objectGUID
  64. samdb_set_ntds_objectGUID
  65. samdb_server_dn
  66. samdb_server_site_dn
  67. samdb_is_pdc
  68. samdb_is_gc
  69. samdb_search_for_parent_domain
  70. samdb_password_complexity_ok
  71. samdb_set_password
  72. samdb_set_password_sid
  73. samdb_create_foreign_security_principal
  74. samdb_dns_domain_to_dn
  75. samdb_domain_to_dn

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Samba utility functions
   4 
   5    Copyright (C) Andrew Tridgell 2004
   6    Copyright (C) Volker Lendecke 2004
   7    Copyright (C) Andrew Bartlett <abartlet@samba.org> 2006
   8    Copyright (C) Jelmer Vernooij <jelmer@samba.org> 2007
   9    
  10    This program is free software; you can redistribute it and/or modify
  11    it under the terms of the GNU General Public License as published by
  12    the Free Software Foundation; either version 3 of the License, or
  13    (at your option) any later version.
  14    
  15    This program is distributed in the hope that it will be useful,
  16    but WITHOUT ANY WARRANTY; without even the implied warranty of
  17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18    GNU General Public License for more details.
  19    
  20    You should have received a copy of the GNU General Public License
  21    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  22 */
  23 
  24 #include "includes.h"
  25 #include "events/events.h"
  26 #include "ldb.h"
  27 #include "ldb_errors.h"
  28 #include "../lib/util/util_ldb.h"
  29 #include "../lib/crypto/crypto.h"
  30 #include "dsdb/samdb/samdb.h"
  31 #include "libcli/security/security.h"
  32 #include "librpc/gen_ndr/ndr_security.h"
  33 #include "librpc/gen_ndr/ndr_misc.h"
  34 #include "dsdb/common/flags.h"
  35 #include "dsdb/common/proto.h"
  36 #include "libcli/ldap/ldap_ndr.h"
  37 #include "param/param.h"
  38 #include "libcli/auth/libcli_auth.h"
  39 
  40 /*
  41   search the sam for the specified attributes in a specific domain, filter on
  42   objectSid being in domain_sid.
  43 */
  44 int samdb_search_domain(struct ldb_context *sam_ldb,
     /* [<][>][^][v][top][bottom][index][help] */
  45                         TALLOC_CTX *mem_ctx, 
  46                         struct ldb_dn *basedn,
  47                         struct ldb_message ***res,
  48                         const char * const *attrs,
  49                         const struct dom_sid *domain_sid,
  50                         const char *format, ...)  _PRINTF_ATTRIBUTE(7,8)
  51 {
  52         va_list ap;
  53         int i, count;
  54 
  55         va_start(ap, format);
  56         count = gendb_search_v(sam_ldb, mem_ctx, basedn,
  57                                res, attrs, format, ap);
  58         va_end(ap);
  59 
  60         i=0;
  61 
  62         while (i<count) {
  63                 struct dom_sid *entry_sid;
  64 
  65                 entry_sid = samdb_result_dom_sid(mem_ctx, (*res)[i], "objectSid");
  66 
  67                 if ((entry_sid == NULL) ||
  68                     (!dom_sid_in_domain(domain_sid, entry_sid))) {
  69                         /* Delete that entry from the result set */
  70                         (*res)[i] = (*res)[count-1];
  71                         count -= 1;
  72                         talloc_free(entry_sid);
  73                         continue;
  74                 }
  75                 talloc_free(entry_sid);
  76                 i += 1;
  77         }
  78 
  79         return count;
  80 }
  81 
  82 /*
  83   search the sam for a single string attribute in exactly 1 record
  84 */
  85 const char *samdb_search_string_v(struct ldb_context *sam_ldb,
     /* [<][>][^][v][top][bottom][index][help] */
  86                                   TALLOC_CTX *mem_ctx,
  87                                   struct ldb_dn *basedn,
  88                                   const char *attr_name,
  89                                   const char *format, va_list ap) _PRINTF_ATTRIBUTE(5,0)
  90 {
  91         int count;
  92         const char *attrs[2] = { NULL, NULL };
  93         struct ldb_message **res = NULL;
  94 
  95         attrs[0] = attr_name;
  96 
  97         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
  98         if (count > 1) {                
  99                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
 100                          attr_name, format, count));
 101         }
 102         if (count != 1) {
 103                 talloc_free(res);
 104                 return NULL;
 105         }
 106 
 107         return samdb_result_string(res[0], attr_name, NULL);
 108 }
 109                                  
 110 
 111 /*
 112   search the sam for a single string attribute in exactly 1 record
 113 */
 114 const char *samdb_search_string(struct ldb_context *sam_ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 115                                 TALLOC_CTX *mem_ctx,
 116                                 struct ldb_dn *basedn,
 117                                 const char *attr_name,
 118                                 const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
 119 {
 120         va_list ap;
 121         const char *str;
 122 
 123         va_start(ap, format);
 124         str = samdb_search_string_v(sam_ldb, mem_ctx, basedn, attr_name, format, ap);
 125         va_end(ap);
 126 
 127         return str;
 128 }
 129 
 130 struct ldb_dn *samdb_search_dn(struct ldb_context *sam_ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 131                                TALLOC_CTX *mem_ctx,
 132                                struct ldb_dn *basedn,
 133                                const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
 134 {
 135         va_list ap;
 136         struct ldb_dn *ret;
 137         struct ldb_message **res = NULL;
 138         int count;
 139 
 140         va_start(ap, format);
 141         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, NULL, format, ap);
 142         va_end(ap);
 143 
 144         if (count != 1) return NULL;
 145 
 146         ret = talloc_steal(mem_ctx, res[0]->dn);
 147         talloc_free(res);
 148 
 149         return ret;
 150 }
 151 
 152 /*
 153   search the sam for a dom_sid attribute in exactly 1 record
 154 */
 155 struct dom_sid *samdb_search_dom_sid(struct ldb_context *sam_ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 156                                      TALLOC_CTX *mem_ctx,
 157                                      struct ldb_dn *basedn,
 158                                      const char *attr_name,
 159                                      const char *format, ...) _PRINTF_ATTRIBUTE(5,6)
 160 {
 161         va_list ap;
 162         int count;
 163         struct ldb_message **res;
 164         const char *attrs[2] = { NULL, NULL };
 165         struct dom_sid *sid;
 166 
 167         attrs[0] = attr_name;
 168 
 169         va_start(ap, format);
 170         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
 171         va_end(ap);
 172         if (count > 1) {                
 173                 DEBUG(1,("samdb: search for %s %s not single valued (count=%d)\n", 
 174                          attr_name, format, count));
 175         }
 176         if (count != 1) {
 177                 talloc_free(res);
 178                 return NULL;
 179         }
 180         sid = samdb_result_dom_sid(mem_ctx, res[0], attr_name);
 181         talloc_free(res);
 182         return sid;     
 183 }
 184 
 185 /*
 186   return the count of the number of records in the sam matching the query
 187 */
 188 int samdb_search_count(struct ldb_context *sam_ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 189                        TALLOC_CTX *mem_ctx,
 190                        struct ldb_dn *basedn,
 191                        const char *format, ...) _PRINTF_ATTRIBUTE(4,5)
 192 {
 193         va_list ap;
 194         struct ldb_message **res;
 195         const char * const attrs[] = { NULL };
 196         int ret;
 197 
 198         va_start(ap, format);
 199         ret = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
 200         va_end(ap);
 201 
 202         return ret;
 203 }
 204 
 205 
 206 /*
 207   search the sam for a single integer attribute in exactly 1 record
 208 */
 209 uint_t samdb_search_uint(struct ldb_context *sam_ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 210                          TALLOC_CTX *mem_ctx,
 211                          uint_t default_value,
 212                          struct ldb_dn *basedn,
 213                          const char *attr_name,
 214                          const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
 215 {
 216         va_list ap;
 217         int count;
 218         struct ldb_message **res;
 219         const char *attrs[2] = { NULL, NULL };
 220 
 221         attrs[0] = attr_name;
 222 
 223         va_start(ap, format);
 224         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
 225         va_end(ap);
 226 
 227         if (count != 1) {
 228                 return default_value;
 229         }
 230 
 231         return samdb_result_uint(res[0], attr_name, default_value);
 232 }
 233 
 234 /*
 235   search the sam for a single signed 64 bit integer attribute in exactly 1 record
 236 */
 237 int64_t samdb_search_int64(struct ldb_context *sam_ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 238                            TALLOC_CTX *mem_ctx,
 239                            int64_t default_value,
 240                            struct ldb_dn *basedn,
 241                            const char *attr_name,
 242                            const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
 243 {
 244         va_list ap;
 245         int count;
 246         struct ldb_message **res;
 247         const char *attrs[2] = { NULL, NULL };
 248 
 249         attrs[0] = attr_name;
 250 
 251         va_start(ap, format);
 252         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
 253         va_end(ap);
 254 
 255         if (count != 1) {
 256                 return default_value;
 257         }
 258 
 259         return samdb_result_int64(res[0], attr_name, default_value);
 260 }
 261 
 262 /*
 263   search the sam for multipe records each giving a single string attribute
 264   return the number of matches, or -1 on error
 265 */
 266 int samdb_search_string_multiple(struct ldb_context *sam_ldb,
     /* [<][>][^][v][top][bottom][index][help] */
 267                                  TALLOC_CTX *mem_ctx,
 268                                  struct ldb_dn *basedn,
 269                                  const char ***strs,
 270                                  const char *attr_name,
 271                                  const char *format, ...) _PRINTF_ATTRIBUTE(6,7)
 272 {
 273         va_list ap;
 274         int count, i;
 275         const char *attrs[2] = { NULL, NULL };
 276         struct ldb_message **res = NULL;
 277 
 278         attrs[0] = attr_name;
 279 
 280         va_start(ap, format);
 281         count = gendb_search_v(sam_ldb, mem_ctx, basedn, &res, attrs, format, ap);
 282         va_end(ap);
 283 
 284         if (count <= 0) {
 285                 return count;
 286         }
 287 
 288         /* make sure its single valued */
 289         for (i=0;i<count;i++) {
 290                 if (res[i]->num_elements != 1) {
 291                         DEBUG(1,("samdb: search for %s %s not single valued\n", 
 292                                  attr_name, format));
 293                         talloc_free(res);
 294                         return -1;
 295                 }
 296         }
 297 
 298         *strs = talloc_array(mem_ctx, const char *, count+1);
 299         if (! *strs) {
 300                 talloc_free(res);
 301                 return -1;
 302         }
 303 
 304         for (i=0;i<count;i++) {
 305                 (*strs)[i] = samdb_result_string(res[i], attr_name, NULL);
 306         }
 307         (*strs)[count] = NULL;
 308 
 309         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)
     /* [<][>][^][v][top][bottom][index][help] */
 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)
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 332                                 const char *default_value)
 333 {
 334         return ldb_msg_find_attr_as_string(msg, attr, default_value);
 335 }
 336 
 337 struct ldb_dn *samdb_result_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 338                                const char *attr, struct ldb_dn *default_value)
 339 {
 340         struct ldb_dn *ret_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
 341         if (!ret_dn) {
 342                 return default_value;
 343         }
 344         return ret_dn;
 345 }
 346 
 347 /*
 348   pull a rid from a objectSid in a result set. 
 349 */
 350 uint32_t samdb_result_rid_from_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
     /* [<][>][^][v][top][bottom][index][help] */
 351                                    const char *attr, uint32_t default_value)
 352 {
 353         struct dom_sid *sid;
 354         uint32_t rid;
 355 
 356         sid = samdb_result_dom_sid(mem_ctx, msg, attr);
 357         if (sid == NULL) {
 358                 return default_value;
 359         }
 360         rid = sid->sub_auths[sid->num_auths-1];
 361         talloc_free(sid);
 362         return rid;
 363 }
 364 
 365 /*
 366   pull a dom_sid structure from a objectSid in a result set. 
 367 */
 368 struct dom_sid *samdb_result_dom_sid(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
     /* [<][>][^][v][top][bottom][index][help] */
 369                                      const char *attr)
 370 {
 371         const struct ldb_val *v;
 372         struct dom_sid *sid;
 373         enum ndr_err_code ndr_err;
 374         v = ldb_msg_find_ldb_val(msg, attr);
 375         if (v == NULL) {
 376                 return NULL;
 377         }
 378         sid = talloc(mem_ctx, struct dom_sid);
 379         if (sid == NULL) {
 380                 return NULL;
 381         }
 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)) {
 385                 talloc_free(sid);
 386                 return NULL;
 387         }
 388         return sid;
 389 }
 390 
 391 /*
 392   pull a guid structure from a objectGUID in a result set. 
 393 */
 394 struct GUID samdb_result_guid(const struct ldb_message *msg, const char *attr)
     /* [<][>][^][v][top][bottom][index][help] */
 395 {
 396         const struct ldb_val *v;
 397         enum ndr_err_code ndr_err;
 398         struct GUID guid;
 399         TALLOC_CTX *mem_ctx;
 400 
 401         ZERO_STRUCT(guid);
 402 
 403         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;
 413         }
 414 
 415         return guid;
 416 }
 417 
 418 /*
 419   pull a sid prefix from a objectSid in a result set. 
 420   this is used to find the domain sid for a user
 421 */
 422 struct dom_sid *samdb_result_sid_prefix(TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
     /* [<][>][^][v][top][bottom][index][help] */
 423                                         const char *attr)
 424 {
 425         struct dom_sid *sid = samdb_result_dom_sid(mem_ctx, msg, attr);
 426         if (!sid || sid->num_auths < 1) return NULL;
 427         sid->num_auths--;
 428         return sid;
 429 }
 430 
 431 /*
 432   pull a NTTIME in a result set. 
 433 */
 434 NTTIME samdb_result_nttime(struct ldb_message *msg, const char *attr, NTTIME default_value)
     /* [<][>][^][v][top][bottom][index][help] */
 435 {
 436         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
 437 }
 438 
 439 /*
 440  * Windows uses both 0 and 9223372036854775807 (0x7FFFFFFFFFFFFFFFULL) to
 441  * indicate an account doesn't expire.
 442  *
 443  * When Windows initially creates an account, it sets
 444  * accountExpires = 9223372036854775807 (0x7FFFFFFFFFFFFFFF).  However,
 445  * when changing from an account having a specific expiration date to
 446  * that account never expiring, it sets accountExpires = 0.
 447  *
 448  * Consolidate that logic here to allow clearer logic for account expiry in
 449  * the rest of the code.
 450  */
 451 NTTIME samdb_result_account_expires(struct ldb_message *msg)
     /* [<][>][^][v][top][bottom][index][help] */
 452 {
 453         NTTIME ret = ldb_msg_find_attr_as_uint64(msg, "accountExpires",
 454                                                  0);
 455 
 456         if (ret == 0)
 457                 ret = 0x7FFFFFFFFFFFFFFFULL;
 458 
 459         return ret;
 460 }
 461 
 462 /*
 463   pull a uint64_t from a result set. 
 464 */
 465 uint64_t samdb_result_uint64(struct ldb_message *msg, const char *attr, uint64_t default_value)
     /* [<][>][^][v][top][bottom][index][help] */
 466 {
 467         return ldb_msg_find_attr_as_uint64(msg, attr, default_value);
 468 }
 469 
 470 
 471 /*
 472   construct the allow_password_change field from the PwdLastSet attribute and the 
 473   domain password settings
 474 */
 475 NTTIME samdb_result_allow_password_change(struct ldb_context *sam_ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
 476                                           TALLOC_CTX *mem_ctx, 
 477                                           struct ldb_dn *domain_dn, 
 478                                           struct ldb_message *msg, 
 479                                           const char *attr)
 480 {
 481         uint64_t attr_time = samdb_result_uint64(msg, attr, 0);
 482         int64_t minPwdAge;
 483 
 484         if (attr_time == 0) {
 485                 return 0;
 486         }
 487 
 488         minPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "minPwdAge", NULL);
 489 
 490         /* yes, this is a -= not a += as minPwdAge is stored as the negative
 491            of the number of 100-nano-seconds */
 492         attr_time -= minPwdAge;
 493 
 494         return attr_time;
 495 }
 496 
 497 /*
 498   construct the force_password_change field from the PwdLastSet
 499   attribute, the userAccountControl and the domain password settings
 500 */
 501 NTTIME samdb_result_force_password_change(struct ldb_context *sam_ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
 502                                           TALLOC_CTX *mem_ctx, 
 503                                           struct ldb_dn *domain_dn, 
 504                                           struct ldb_message *msg)
 505 {
 506         uint64_t attr_time = samdb_result_uint64(msg, "pwdLastSet", 0);
 507         uint32_t userAccountControl = samdb_result_uint64(msg, "userAccountControl", 0);
 508         int64_t maxPwdAge;
 509 
 510         /* Machine accounts don't expire, and there is a flag for 'no expiry' */
 511         if (!(userAccountControl & UF_NORMAL_ACCOUNT)
 512             || (userAccountControl & UF_DONT_EXPIRE_PASSWD)) {
 513                 return 0x7FFFFFFFFFFFFFFFULL;
 514         }
 515 
 516         if (attr_time == 0) {
 517                 return 0;
 518         }
 519 
 520         maxPwdAge = samdb_search_int64(sam_ldb, mem_ctx, 0, domain_dn, "maxPwdAge", NULL);
 521         if (maxPwdAge == 0) {
 522                 return 0x7FFFFFFFFFFFFFFFULL;
 523         } else {
 524                 attr_time -= maxPwdAge;
 525         }
 526 
 527         return attr_time;
 528 }
 529 
 530 /*
 531   pull a samr_Password structutre from a result set. 
 532 */
 533 struct samr_Password *samdb_result_hash(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
     /* [<][>][^][v][top][bottom][index][help] */
 534 {
 535         struct samr_Password *hash = NULL;
 536         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
 537         if (val && (val->length >= sizeof(hash->hash))) {
 538                 hash = talloc(mem_ctx, struct samr_Password);
 539                 memcpy(hash->hash, val->data, MIN(val->length, sizeof(hash->hash)));
 540         }
 541         return hash;
 542 }
 543 
 544 /*
 545   pull an array of samr_Password structutres from a result set. 
 546 */
 547 uint_t samdb_result_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg, 
     /* [<][>][^][v][top][bottom][index][help] */
 548                            const char *attr, struct samr_Password **hashes)
 549 {
 550         uint_t count = 0;
 551         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
 552         int i;
 553 
 554         *hashes = NULL;
 555         if (!val) {
 556                 return 0;
 557         }
 558         count = val->length / 16;
 559         if (count == 0) {
 560                 return 0;
 561         }
 562 
 563         *hashes = talloc_array(mem_ctx, struct samr_Password, count);
 564         if (! *hashes) {
 565                 return 0;
 566         }
 567 
 568         for (i=0;i<count;i++) {
 569                 memcpy((*hashes)[i].hash, (i*16)+(char *)val->data, 16);
 570         }
 571 
 572         return count;
 573 }
 574 
 575 NTSTATUS samdb_result_passwords(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx, struct ldb_message *msg, 
     /* [<][>][^][v][top][bottom][index][help] */
 576                                 struct samr_Password **lm_pwd, struct samr_Password **nt_pwd) 
 577 {
 578         struct samr_Password *lmPwdHash, *ntPwdHash;
 579         if (nt_pwd) {
 580                 int num_nt;
 581                 num_nt = samdb_result_hashes(mem_ctx, msg, "unicodePwd", &ntPwdHash);
 582                 if (num_nt == 0) {
 583                         *nt_pwd = NULL;
 584                 } else if (num_nt > 1) {
 585                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
 586                 } else {
 587                         *nt_pwd = &ntPwdHash[0];
 588                 }
 589         }
 590         if (lm_pwd) {
 591                 /* Ensure that if we have turned off LM
 592                  * authentication, that we never use the LM hash, even
 593                  * if we store it */
 594                 if (lp_lanman_auth(lp_ctx)) {
 595                         int num_lm;
 596                         num_lm = samdb_result_hashes(mem_ctx, msg, "dBCSPwd", &lmPwdHash);
 597                         if (num_lm == 0) {
 598                                 *lm_pwd = NULL;
 599                         } else if (num_lm > 1) {
 600                                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
 601                         } else {
 602                                 *lm_pwd = &lmPwdHash[0];
 603                         }
 604                 } else {
 605                         *lm_pwd = NULL;
 606                 }
 607         }
 608         return NT_STATUS_OK;
 609 }
 610 
 611 /*
 612   pull a samr_LogonHours structutre from a result set. 
 613 */
 614 struct samr_LogonHours samdb_result_logon_hours(TALLOC_CTX *mem_ctx, struct ldb_message *msg, const char *attr)
     /* [<][>][^][v][top][bottom][index][help] */
 615 {
 616         struct samr_LogonHours hours;
 617         const int units_per_week = 168;
 618         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
 619         ZERO_STRUCT(hours);
 620         hours.bits = talloc_array(mem_ctx, uint8_t, units_per_week);
 621         if (!hours.bits) {
 622                 return hours;
 623         }
 624         hours.units_per_week = units_per_week;
 625         memset(hours.bits, 0xFF, units_per_week);
 626         if (val) {
 627                 memcpy(hours.bits, val->data, MIN(val->length, units_per_week));
 628         }
 629         return hours;
 630 }
 631 
 632 /*
 633   pull a set of account_flags from a result set. 
 634 
 635   This requires that the attributes: 
 636    pwdLastSet
 637    userAccountControl
 638   be included in 'msg'
 639 */
 640 uint32_t samdb_result_acct_flags(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
 641                                  struct ldb_message *msg, struct ldb_dn *domain_dn)
 642 {
 643         uint32_t userAccountControl = ldb_msg_find_attr_as_uint(msg, "userAccountControl", 0);
 644         uint32_t acct_flags = samdb_uf2acb(userAccountControl); 
 645         NTTIME must_change_time;
 646         NTTIME now;
 647         
 648         must_change_time = samdb_result_force_password_change(sam_ctx, mem_ctx, 
 649                                                               domain_dn, msg);
 650         
 651         /* Test account expire time */
 652         unix_to_nt_time(&now, time(NULL));
 653         /* check for expired password */
 654         if (must_change_time < now) {
 655                 acct_flags |= ACB_PW_EXPIRED;
 656         }
 657         return acct_flags;
 658 }
 659 
 660 struct lsa_BinaryString samdb_result_parameters(TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
 661                                                 struct ldb_message *msg,
 662                                                 const char *attr)
 663 {
 664         struct lsa_BinaryString s;
 665         const struct ldb_val *val = ldb_msg_find_ldb_val(msg, attr);
 666 
 667         ZERO_STRUCT(s);
 668 
 669         if (!val) {
 670                 return s;
 671         }
 672 
 673         s.array = talloc_array(mem_ctx, uint16_t, val->length/2);
 674         if (!s.array) {
 675                 return s;
 676         }
 677         s.length = s.size = val->length/2;
 678         memcpy(s.array, val->data, val->length);
 679 
 680         return s;
 681 }
 682 
 683 /* Find an attribute, with a particular value */
 684 
 685 /* The current callers of this function expect a very specific
 686  * behaviour: In particular, objectClass subclass equivilance is not
 687  * wanted.  This means that we should not lookup the schema for the
 688  * comparison function */
 689 struct ldb_message_element *samdb_find_attribute(struct ldb_context *ldb, 
     /* [<][>][^][v][top][bottom][index][help] */
 690                                                  const struct ldb_message *msg, 
 691                                                  const char *name, const char *value)
 692 {
 693         int i;
 694         struct ldb_message_element *el = ldb_msg_find_element(msg, name);
 695 
 696         if (!el) {
 697                 return NULL;
 698         }
 699 
 700         for (i=0;i<el->num_values;i++) {
 701                 if (ldb_attr_cmp(value, (char *)el->values[i].data) == 0) {
 702                         return el;
 703                 }
 704         }
 705 
 706         return NULL;
 707 }
 708 
 709 int samdb_find_or_add_value(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
     /* [<][>][^][v][top][bottom][index][help] */
 710 {
 711         if (samdb_find_attribute(ldb, msg, name, set_value) == NULL) {
 712                 return samdb_msg_add_string(ldb, msg, msg, name, set_value);
 713         }
 714         return LDB_SUCCESS;
 715 }
 716 
 717 int samdb_find_or_add_attribute(struct ldb_context *ldb, struct ldb_message *msg, const char *name, const char *set_value)
     /* [<][>][^][v][top][bottom][index][help] */
 718 {
 719         struct ldb_message_element *el;
 720 
 721         el = ldb_msg_find_element(msg, name);
 722         if (el) {
 723                 return LDB_SUCCESS;
 724         }
 725                 
 726         return samdb_msg_add_string(ldb, msg, msg, name, set_value);
 727 }
 728 
 729 
 730 
 731 /*
 732   add a string element to a message
 733 */
 734 int samdb_msg_add_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 735                          const char *attr_name, const char *str)
 736 {
 737         char *s = talloc_strdup(mem_ctx, str);
 738         char *a = talloc_strdup(mem_ctx, attr_name);
 739         if (s == NULL || a == NULL) {
 740                 return LDB_ERR_OPERATIONS_ERROR;
 741         }
 742         return ldb_msg_add_string(msg, a, s);
 743 }
 744 
 745 /*
 746   add a dom_sid element to a message
 747 */
 748 int samdb_msg_add_dom_sid(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 749                          const char *attr_name, struct dom_sid *sid)
 750 {
 751         struct ldb_val v;
 752         enum ndr_err_code ndr_err;
 753 
 754         ndr_err = ndr_push_struct_blob(&v, mem_ctx, 
 755                                        lp_iconv_convenience(ldb_get_opaque(sam_ldb, "loadparm")),
 756                                        sid,
 757                                        (ndr_push_flags_fn_t)ndr_push_dom_sid);
 758         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
 759                 return -1;
 760         }
 761         return ldb_msg_add_value(msg, attr_name, &v, NULL);
 762 }
 763 
 764 
 765 /*
 766   add a delete element operation to a message
 767 */
 768 int samdb_msg_add_delete(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 769                          const char *attr_name)
 770 {
 771         /* we use an empty replace rather than a delete, as it allows for 
 772            samdb_replace() to be used everywhere */
 773         return ldb_msg_add_empty(msg, attr_name, LDB_FLAG_MOD_REPLACE, NULL);
 774 }
 775 
 776 /*
 777   add a add attribute value to a message
 778 */
 779 int samdb_msg_add_addval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 780                          const char *attr_name, const char *value)
 781 {
 782         struct ldb_message_element *el;
 783         char *a, *v;
 784         int ret;
 785         a = talloc_strdup(mem_ctx, attr_name);
 786         if (a == NULL)
 787                 return -1;
 788         v = talloc_strdup(mem_ctx, value);
 789         if (v == NULL)
 790                 return -1;
 791         ret = ldb_msg_add_string(msg, a, v);
 792         if (ret != 0)
 793                 return ret;
 794         el = ldb_msg_find_element(msg, a);
 795         if (el == NULL)
 796                 return -1;
 797         el->flags = LDB_FLAG_MOD_ADD;
 798         return 0;
 799 }
 800 
 801 /*
 802   add a delete attribute value to a message
 803 */
 804 int samdb_msg_add_delval(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 805                          const char *attr_name, const char *value)
 806 {
 807         struct ldb_message_element *el;
 808         char *a, *v;
 809         int ret;
 810         a = talloc_strdup(mem_ctx, attr_name);
 811         if (a == NULL)
 812                 return -1;
 813         v = talloc_strdup(mem_ctx, value);
 814         if (v == NULL)
 815                 return -1;
 816         ret = ldb_msg_add_string(msg, a, v);
 817         if (ret != 0)
 818                 return ret;
 819         el = ldb_msg_find_element(msg, a);
 820         if (el == NULL)
 821                 return -1;
 822         el->flags = LDB_FLAG_MOD_DELETE;
 823         return 0;
 824 }
 825 
 826 /*
 827   add a int element to a message
 828 */
 829 int samdb_msg_add_int(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 830                        const char *attr_name, int v)
 831 {
 832         const char *s = talloc_asprintf(mem_ctx, "%d", v);
 833         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
 834 }
 835 
 836 /*
 837   add a uint_t element to a message
 838 */
 839 int samdb_msg_add_uint(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 840                        const char *attr_name, uint_t v)
 841 {
 842         const char *s = talloc_asprintf(mem_ctx, "%u", v);
 843         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
 844 }
 845 
 846 /*
 847   add a (signed) int64_t element to a message
 848 */
 849 int samdb_msg_add_int64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 850                         const char *attr_name, int64_t v)
 851 {
 852         const char *s = talloc_asprintf(mem_ctx, "%lld", (long long)v);
 853         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
 854 }
 855 
 856 /*
 857   add a uint64_t element to a message
 858 */
 859 int samdb_msg_add_uint64(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 860                         const char *attr_name, uint64_t v)
 861 {
 862         const char *s = talloc_asprintf(mem_ctx, "%llu", (unsigned long long)v);
 863         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, s);
 864 }
 865 
 866 /*
 867   add a samr_Password element to a message
 868 */
 869 int samdb_msg_add_hash(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 870                        const char *attr_name, struct samr_Password *hash)
 871 {
 872         struct ldb_val val;
 873         val.data = talloc_memdup(mem_ctx, hash->hash, 16);
 874         if (!val.data) {
 875                 return -1;
 876         }
 877         val.length = 16;
 878         return ldb_msg_add_value(msg, attr_name, &val, NULL);
 879 }
 880 
 881 /*
 882   add a samr_Password array to a message
 883 */
 884 int samdb_msg_add_hashes(TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 885                          const char *attr_name, struct samr_Password *hashes, uint_t count)
 886 {
 887         struct ldb_val val;
 888         int i;
 889         val.data = talloc_array_size(mem_ctx, 16, count);
 890         val.length = count*16;
 891         if (!val.data) {
 892                 return -1;
 893         }
 894         for (i=0;i<count;i++) {
 895                 memcpy(i*16 + (char *)val.data, hashes[i].hash, 16);
 896         }
 897         return ldb_msg_add_value(msg, attr_name, &val, NULL);
 898 }
 899 
 900 /*
 901   add a acct_flags element to a message
 902 */
 903 int samdb_msg_add_acct_flags(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 904                              const char *attr_name, uint32_t v)
 905 {
 906         return samdb_msg_add_uint(sam_ldb, mem_ctx, msg, attr_name, samdb_acb2uf(v));
 907 }
 908 
 909 /*
 910   add a logon_hours element to a message
 911 */
 912 int samdb_msg_add_logon_hours(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 913                               const char *attr_name, struct samr_LogonHours *hours)
 914 {
 915         struct ldb_val val;
 916         val.length = hours->units_per_week / 8;
 917         val.data = hours->bits;
 918         return ldb_msg_add_value(msg, attr_name, &val, NULL);
 919 }
 920 
 921 /*
 922   add a parameters element to a message
 923 */
 924 int samdb_msg_add_parameters(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 925                              const char *attr_name, struct lsa_BinaryString *parameters)
 926 {
 927         struct ldb_val val;
 928         val.length = parameters->length * 2;
 929         val.data = (uint8_t *)parameters->array;
 930         return ldb_msg_add_value(msg, attr_name, &val, NULL);
 931 }
 932 /*
 933   add a general value element to a message
 934 */
 935 int samdb_msg_add_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 936                               const char *attr_name, const struct ldb_val *val)
 937 {
 938         return ldb_msg_add_value(msg, attr_name, val, NULL);
 939 }
 940 
 941 /*
 942   sets a general value element to a message
 943 */
 944 int samdb_msg_set_value(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 945                         const char *attr_name, const struct ldb_val *val)
 946 {
 947         struct ldb_message_element *el;
 948 
 949         el = ldb_msg_find_element(msg, attr_name);
 950         if (el) {
 951                 el->num_values = 0;
 952         }
 953         return ldb_msg_add_value(msg, attr_name, val, NULL);
 954 }
 955 
 956 /*
 957   set a string element in a message
 958 */
 959 int samdb_msg_set_string(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg,
     /* [<][>][^][v][top][bottom][index][help] */
 960                          const char *attr_name, const char *str)
 961 {
 962         struct ldb_message_element *el;
 963 
 964         el = ldb_msg_find_element(msg, attr_name);
 965         if (el) {
 966                 el->num_values = 0;
 967         }
 968         return samdb_msg_add_string(sam_ldb, mem_ctx, msg, attr_name, str);
 969 }
 970 
 971 /*
 972   replace elements in a record
 973 */
 974 int samdb_replace(struct ldb_context *sam_ldb, TALLOC_CTX *mem_ctx, struct ldb_message *msg)
     /* [<][>][^][v][top][bottom][index][help] */
 975 {
 976         int i;
 977 
 978         /* mark all the message elements as LDB_FLAG_MOD_REPLACE */
 979         for (i=0;i<msg->num_elements;i++) {
 980                 msg->elements[i].flags = LDB_FLAG_MOD_REPLACE;
 981         }
 982 
 983         /* modify the samdb record */
 984         return ldb_modify(sam_ldb, msg);
 985 }
 986 
 987 /*
 988   return a default security descriptor
 989 */
 990 struct security_descriptor *samdb_default_security_descriptor(TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
 991 {
 992         struct security_descriptor *sd;
 993 
 994         sd = security_descriptor_initialise(mem_ctx);
 995 
 996         return sd;
 997 }
 998 
 999 struct ldb_dn *samdb_base_dn(struct ldb_context *sam_ctx) 
     /* [<][>][^][v][top][bottom][index][help] */
1000 {
1001         return ldb_get_default_basedn(sam_ctx);
1002 }
1003 
1004 struct ldb_dn *samdb_config_dn(struct ldb_context *sam_ctx) 
     /* [<][>][^][v][top][bottom][index][help] */
1005 {
1006         return ldb_get_config_basedn(sam_ctx);
1007 }
1008 
1009 struct ldb_dn *samdb_schema_dn(struct ldb_context *sam_ctx) 
     /* [<][>][^][v][top][bottom][index][help] */
1010 {
1011         return ldb_get_schema_basedn(sam_ctx);
1012 }
1013 
1014 struct ldb_dn *samdb_root_dn(struct ldb_context *sam_ctx) 
     /* [<][>][^][v][top][bottom][index][help] */
1015 {
1016         return ldb_get_root_basedn(sam_ctx);
1017 }
1018 
1019 struct ldb_dn *samdb_partitions_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
1020 {
1021         struct ldb_dn *new_dn;
1022 
1023         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1024         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Partitions")) {
1025                 talloc_free(new_dn);
1026                 return NULL;
1027         }
1028         return new_dn;
1029 }
1030 
1031 struct ldb_dn *samdb_sites_dn(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
1032 {
1033         struct ldb_dn *new_dn;
1034 
1035         new_dn = ldb_dn_copy(mem_ctx, samdb_config_dn(sam_ctx));
1036         if ( ! ldb_dn_add_child_fmt(new_dn, "CN=Sites")) {
1037                 talloc_free(new_dn);
1038                 return NULL;
1039         }
1040         return new_dn;
1041 }
1042 
1043 /*
1044   work out the domain sid for the current open ldb
1045 */
1046 const struct dom_sid *samdb_domain_sid(struct ldb_context *ldb)
     /* [<][>][^][v][top][bottom][index][help] */
1047 {
1048         TALLOC_CTX *tmp_ctx;
1049         const struct dom_sid *domain_sid;
1050         const char *attrs[] = {
1051                 "objectSid",
1052                 NULL
1053         };
1054         struct ldb_result *res;
1055         int ret;
1056 
1057         /* see if we have a cached copy */
1058         domain_sid = (struct dom_sid *)ldb_get_opaque(ldb, "cache.domain_sid");
1059         if (domain_sid) {
1060                 return domain_sid;
1061         }
1062 
1063         tmp_ctx = talloc_new(ldb);
1064         if (tmp_ctx == NULL) {
1065                 goto failed;
1066         }
1067 
1068         ret = ldb_search(ldb, tmp_ctx, &res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, attrs, "objectSid=*");
1069 
1070         if (ret != LDB_SUCCESS) {
1071                 goto failed;
1072         }
1073         
1074         if (res->count != 1) {
1075                 goto failed;
1076         }
1077 
1078         domain_sid = samdb_result_dom_sid(tmp_ctx, res->msgs[0], "objectSid");
1079         if (domain_sid == NULL) {
1080                 goto failed;
1081         }
1082 
1083         /* cache the domain_sid in the ldb */
1084         if (ldb_set_opaque(ldb, "cache.domain_sid", discard_const_p(struct dom_sid, domain_sid)) != LDB_SUCCESS) {
1085                 goto failed;
1086         }
1087 
1088         talloc_steal(ldb, domain_sid);
1089         talloc_free(tmp_ctx);
1090 
1091         return domain_sid;
1092 
1093 failed:
1094         DEBUG(1,("Failed to find domain_sid for open ldb\n"));
1095         talloc_free(tmp_ctx);
1096         return NULL;
1097 }
1098 
1099 bool samdb_set_domain_sid(struct ldb_context *ldb, const struct dom_sid *dom_sid_in)
     /* [<][>][^][v][top][bottom][index][help] */
1100 {
1101         TALLOC_CTX *tmp_ctx;
1102         struct dom_sid *dom_sid_new;
1103         struct dom_sid *dom_sid_old;
1104 
1105         /* see if we have a cached copy */
1106         dom_sid_old = talloc_get_type(ldb_get_opaque(ldb, 
1107                                                      "cache.domain_sid"), struct dom_sid);
1108 
1109         tmp_ctx = talloc_new(ldb);
1110         if (tmp_ctx == NULL) {
1111                 goto failed;
1112         }
1113 
1114         dom_sid_new = dom_sid_dup(tmp_ctx, dom_sid_in);
1115         if (!dom_sid_new) {
1116                 goto failed;
1117         }
1118 
1119         /* cache the domain_sid in the ldb */
1120         if (ldb_set_opaque(ldb, "cache.domain_sid", dom_sid_new) != LDB_SUCCESS) {
1121                 goto failed;
1122         }
1123 
1124         talloc_steal(ldb, dom_sid_new);
1125         talloc_free(tmp_ctx);
1126         talloc_free(dom_sid_old);
1127 
1128         return true;
1129 
1130 failed:
1131         DEBUG(1,("Failed to set our own cached domain SID in the ldb!\n"));
1132         talloc_free(tmp_ctx);
1133         return false;
1134 }
1135 
1136 /* Obtain the short name of the flexible single master operator
1137  * (FSMO), such as the PDC Emulator */
1138 const char *samdb_result_fsmo_name(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, 
     /* [<][>][^][v][top][bottom][index][help] */
1139                              const char *attr)
1140 {
1141         /* Format is cn=NTDS Settings,cn=<NETBIOS name of FSMO>,.... */
1142         struct ldb_dn *fsmo_dn = ldb_msg_find_attr_as_dn(ldb, mem_ctx, msg, attr);
1143         const struct ldb_val *val = ldb_dn_get_component_val(fsmo_dn, 1);
1144         const char *name = ldb_dn_get_component_name(fsmo_dn, 1);
1145 
1146         if (!name || (ldb_attr_cmp(name, "cn") != 0)) {
1147                 /* Ensure this matches the format.  This gives us a
1148                  * bit more confidence that a 'cn' value will be a
1149                  * ascii string */
1150                 return NULL;
1151         }
1152         if (val) {
1153                 return (char *)val->data;
1154         }
1155         return NULL;
1156 }
1157 
1158 /*
1159   work out the ntds settings dn for the current open ldb
1160 */
1161 struct ldb_dn *samdb_ntds_settings_dn(struct ldb_context *ldb)
     /* [<][>][^][v][top][bottom][index][help] */
1162 {
1163         TALLOC_CTX *tmp_ctx;
1164         const char *root_attrs[] = { "dsServiceName", NULL };
1165         int ret;
1166         struct ldb_result *root_res;
1167         struct ldb_dn *settings_dn;
1168         
1169         /* see if we have a cached copy */
1170         settings_dn = (struct ldb_dn *)ldb_get_opaque(ldb, "cache.settings_dn");
1171         if (settings_dn) {
1172                 return settings_dn;
1173         }
1174 
1175         tmp_ctx = talloc_new(ldb);
1176         if (tmp_ctx == NULL) {
1177                 goto failed;
1178         }
1179         
1180 
1181         ret = ldb_search(ldb, tmp_ctx, &root_res, ldb_dn_new(tmp_ctx, ldb, ""), LDB_SCOPE_BASE, root_attrs, NULL);
1182         if (ret) {
1183                 DEBUG(1,("Searching for dsServiceName in rootDSE failed: %s\n", 
1184                          ldb_errstring(ldb)));
1185                 goto failed;
1186         }
1187 
1188         if (root_res->count != 1) {
1189                 goto failed;
1190         }
1191 
1192         settings_dn = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, root_res->msgs[0], "dsServiceName");
1193 
1194         /* cache the domain_sid in the ldb */
1195         if (ldb_set_opaque(ldb, "cache.settings_dn", settings_dn) != LDB_SUCCESS) {
1196                 goto failed;
1197         }
1198 
1199         talloc_steal(ldb, settings_dn);
1200         talloc_free(tmp_ctx);
1201 
1202         return settings_dn;
1203 
1204 failed:
1205         DEBUG(1,("Failed to find our own NTDS Settings DN in the ldb!\n"));
1206         talloc_free(tmp_ctx);
1207         return NULL;
1208 }
1209 
1210 /*
1211   work out the ntds settings invocationId for the current open ldb
1212 */
1213 const struct GUID *samdb_ntds_invocation_id(struct ldb_context *ldb)
     /* [<][>][^][v][top][bottom][index][help] */
1214 {
1215         TALLOC_CTX *tmp_ctx;
1216         const char *attrs[] = { "invocationId", NULL };
1217         int ret;
1218         struct ldb_result *res;
1219         struct GUID *invocation_id;
1220         
1221         /* see if we have a cached copy */
1222         invocation_id = (struct GUID *)ldb_get_opaque(ldb, "cache.invocation_id");
1223         if (invocation_id) {
1224                 return invocation_id;
1225         }
1226 
1227         tmp_ctx = talloc_new(ldb);
1228         if (tmp_ctx == NULL) {
1229                 goto failed;
1230         }
1231 
1232         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1233         if (ret) {
1234                 goto failed;
1235         }
1236 
1237         if (res->count != 1) {
1238                 goto failed;
1239         }
1240 
1241         invocation_id = talloc(tmp_ctx, struct GUID);
1242         if (!invocation_id) {
1243                 goto failed;
1244         }
1245 
1246         *invocation_id = samdb_result_guid(res->msgs[0], "invocationId");
1247 
1248         /* cache the domain_sid in the ldb */
1249         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id) != LDB_SUCCESS) {
1250                 goto failed;
1251         }
1252 
1253         talloc_steal(ldb, invocation_id);
1254         talloc_free(tmp_ctx);
1255 
1256         return invocation_id;
1257 
1258 failed:
1259         DEBUG(1,("Failed to find our own NTDS Settings invocationId in the ldb!\n"));
1260         talloc_free(tmp_ctx);
1261         return NULL;
1262 }
1263 
1264 bool samdb_set_ntds_invocation_id(struct ldb_context *ldb, const struct GUID *invocation_id_in)
     /* [<][>][^][v][top][bottom][index][help] */
1265 {
1266         TALLOC_CTX *tmp_ctx;
1267         struct GUID *invocation_id_new;
1268         struct GUID *invocation_id_old;
1269 
1270         /* see if we have a cached copy */
1271         invocation_id_old = (struct GUID *)ldb_get_opaque(ldb, 
1272                                                          "cache.invocation_id");
1273 
1274         tmp_ctx = talloc_new(ldb);
1275         if (tmp_ctx == NULL) {
1276                 goto failed;
1277         }
1278 
1279         invocation_id_new = talloc(tmp_ctx, struct GUID);
1280         if (!invocation_id_new) {
1281                 goto failed;
1282         }
1283 
1284         *invocation_id_new = *invocation_id_in;
1285 
1286         /* cache the domain_sid in the ldb */
1287         if (ldb_set_opaque(ldb, "cache.invocation_id", invocation_id_new) != LDB_SUCCESS) {
1288                 goto failed;
1289         }
1290 
1291         talloc_steal(ldb, invocation_id_new);
1292         talloc_free(tmp_ctx);
1293         talloc_free(invocation_id_old);
1294 
1295         return true;
1296 
1297 failed:
1298         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1299         talloc_free(tmp_ctx);
1300         return false;
1301 }
1302 
1303 /*
1304   work out the ntds settings objectGUID for the current open ldb
1305 */
1306 const struct GUID *samdb_ntds_objectGUID(struct ldb_context *ldb)
     /* [<][>][^][v][top][bottom][index][help] */
1307 {
1308         TALLOC_CTX *tmp_ctx;
1309         const char *attrs[] = { "objectGUID", NULL };
1310         int ret;
1311         struct ldb_result *res;
1312         struct GUID *ntds_guid;
1313         
1314         /* see if we have a cached copy */
1315         ntds_guid = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1316         if (ntds_guid) {
1317                 return ntds_guid;
1318         }
1319 
1320         tmp_ctx = talloc_new(ldb);
1321         if (tmp_ctx == NULL) {
1322                 goto failed;
1323         }
1324 
1325         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1326         if (ret) {
1327                 goto failed;
1328         }
1329 
1330         if (res->count != 1) {
1331                 goto failed;
1332         }
1333 
1334         ntds_guid = talloc(tmp_ctx, struct GUID);
1335         if (!ntds_guid) {
1336                 goto failed;
1337         }
1338 
1339         *ntds_guid = samdb_result_guid(res->msgs[0], "objectGUID");
1340 
1341         /* cache the domain_sid in the ldb */
1342         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid) != LDB_SUCCESS) {
1343                 goto failed;
1344         }
1345 
1346         talloc_steal(ldb, ntds_guid);
1347         talloc_free(tmp_ctx);
1348 
1349         return ntds_guid;
1350 
1351 failed:
1352         DEBUG(1,("Failed to find our own NTDS Settings objectGUID in the ldb!\n"));
1353         talloc_free(tmp_ctx);
1354         return NULL;
1355 }
1356 
1357 bool samdb_set_ntds_objectGUID(struct ldb_context *ldb, const struct GUID *ntds_guid_in)
     /* [<][>][^][v][top][bottom][index][help] */
1358 {
1359         TALLOC_CTX *tmp_ctx;
1360         struct GUID *ntds_guid_new;
1361         struct GUID *ntds_guid_old;
1362         
1363         /* see if we have a cached copy */
1364         ntds_guid_old = (struct GUID *)ldb_get_opaque(ldb, "cache.ntds_guid");
1365 
1366         tmp_ctx = talloc_new(ldb);
1367         if (tmp_ctx == NULL) {
1368                 goto failed;
1369         }
1370 
1371         ntds_guid_new = talloc(tmp_ctx, struct GUID);
1372         if (!ntds_guid_new) {
1373                 goto failed;
1374         }
1375 
1376         *ntds_guid_new = *ntds_guid_in;
1377 
1378         /* cache the domain_sid in the ldb */
1379         if (ldb_set_opaque(ldb, "cache.ntds_guid", ntds_guid_new) != LDB_SUCCESS) {
1380                 goto failed;
1381         }
1382 
1383         talloc_steal(ldb, ntds_guid_new);
1384         talloc_free(tmp_ctx);
1385         talloc_free(ntds_guid_old);
1386 
1387         return true;
1388 
1389 failed:
1390         DEBUG(1,("Failed to set our own cached invocationId in the ldb!\n"));
1391         talloc_free(tmp_ctx);
1392         return false;
1393 }
1394 
1395 /*
1396   work out the server dn for the current open ldb
1397 */
1398 struct ldb_dn *samdb_server_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
1399 {
1400         return ldb_dn_get_parent(mem_ctx, samdb_ntds_settings_dn(ldb));
1401 }
1402 
1403 /*
1404   work out the server dn for the current open ldb
1405 */
1406 struct ldb_dn *samdb_server_site_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx)
     /* [<][>][^][v][top][bottom][index][help] */
1407 {
1408         struct ldb_dn *server_dn;
1409         struct ldb_dn *server_site_dn;
1410 
1411         server_dn = samdb_server_dn(ldb, mem_ctx);
1412         if (!server_dn) return NULL;
1413 
1414         server_site_dn = ldb_dn_get_parent(mem_ctx, server_dn);
1415 
1416         talloc_free(server_dn);
1417         return server_site_dn;
1418 }
1419 
1420 /*
1421   work out if we are the PDC for the domain of the current open ldb
1422 */
1423 bool samdb_is_pdc(struct ldb_context *ldb)
     /* [<][>][^][v][top][bottom][index][help] */
1424 {
1425         const char *dom_attrs[] = { "fSMORoleOwner", NULL };
1426         int ret;
1427         struct ldb_result *dom_res;
1428         TALLOC_CTX *tmp_ctx;
1429         bool is_pdc;
1430         struct ldb_dn *pdc;
1431 
1432         tmp_ctx = talloc_new(ldb);
1433         if (tmp_ctx == NULL) {
1434                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1435                 return false;
1436         }
1437 
1438         ret = ldb_search(ldb, tmp_ctx, &dom_res, ldb_get_default_basedn(ldb), LDB_SCOPE_BASE, dom_attrs, NULL);
1439         if (ret) {
1440                 DEBUG(1,("Searching for fSMORoleOwner in %s failed: %s\n", 
1441                          ldb_dn_get_linearized(ldb_get_default_basedn(ldb)), 
1442                          ldb_errstring(ldb)));
1443                 goto failed;
1444         }
1445         if (dom_res->count != 1) {
1446                 goto failed;
1447         }
1448 
1449         pdc = ldb_msg_find_attr_as_dn(ldb, tmp_ctx, dom_res->msgs[0], "fSMORoleOwner");
1450 
1451         if (ldb_dn_compare(samdb_ntds_settings_dn(ldb), pdc) == 0) {
1452                 is_pdc = true;
1453         } else {
1454                 is_pdc = false;
1455         }
1456 
1457         talloc_free(tmp_ctx);
1458 
1459         return is_pdc;
1460 
1461 failed:
1462         DEBUG(1,("Failed to find if we are the PDC for this ldb\n"));
1463         talloc_free(tmp_ctx);
1464         return false;
1465 }
1466 
1467 /*
1468   work out if we are a Global Catalog server for the domain of the current open ldb
1469 */
1470 bool samdb_is_gc(struct ldb_context *ldb)
     /* [<][>][^][v][top][bottom][index][help] */
1471 {
1472         const char *attrs[] = { "options", NULL };
1473         int ret, options;
1474         struct ldb_result *res;
1475         TALLOC_CTX *tmp_ctx;
1476 
1477         tmp_ctx = talloc_new(ldb);
1478         if (tmp_ctx == NULL) {
1479                 DEBUG(1, ("talloc_new failed in samdb_is_pdc"));
1480                 return false;
1481         }
1482 
1483         /* Query cn=ntds settings,.... */
1484         ret = ldb_search(ldb, tmp_ctx, &res, samdb_ntds_settings_dn(ldb), LDB_SCOPE_BASE, attrs, NULL);
1485         if (ret) {
1486                 talloc_free(tmp_ctx);
1487                 return false;
1488         }
1489         if (res->count != 1) {
1490                 talloc_free(tmp_ctx);
1491                 return false;
1492         }
1493 
1494         options = ldb_msg_find_attr_as_int(res->msgs[0], "options", 0);
1495         talloc_free(tmp_ctx);
1496 
1497         /* if options attribute has the 0x00000001 flag set, then enable the global catlog */
1498         if (options & 0x000000001) {
1499                 return true;
1500         }
1501         return false;
1502 }
1503 
1504 /* Find a domain object in the parents of a particular DN.  */
1505 int samdb_search_for_parent_domain(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, struct ldb_dn *dn,
     /* [<][>][^][v][top][bottom][index][help] */
1506                                    struct ldb_dn **parent_dn, const char **errstring)
1507 {
1508         TALLOC_CTX *local_ctx;
1509         struct ldb_dn *sdn = dn;
1510         struct ldb_result *res = NULL;
1511         int ret = 0;
1512         const char *attrs[] = { NULL };
1513 
1514         local_ctx = talloc_new(mem_ctx);
1515         if (local_ctx == NULL) return LDB_ERR_OPERATIONS_ERROR;
1516         
1517         while ((sdn = ldb_dn_get_parent(local_ctx, sdn))) {
1518                 ret = ldb_search(ldb, local_ctx, &res, sdn, LDB_SCOPE_BASE, attrs,
1519                                  "(|(|(objectClass=domain)(objectClass=builtinDomain))(objectClass=samba4LocalDomain))");
1520                 if (ret == LDB_SUCCESS) {
1521                         if (res->count == 1) {
1522                                 break;
1523                         }
1524                 } else {
1525                         break;
1526                 }
1527         }
1528 
1529         if (ret != LDB_SUCCESS) {
1530                 *errstring = talloc_asprintf(mem_ctx, "Error searching for parent domain of %s, failed searching for %s: %s",
1531                                              ldb_dn_get_linearized(dn),
1532                                              ldb_dn_get_linearized(sdn),
1533                                              ldb_errstring(ldb));
1534                 talloc_free(local_ctx);
1535                 return ret;
1536         }
1537         if (res->count != 1) {
1538                 *errstring = talloc_asprintf(mem_ctx, "Invalid dn (%s), not child of a domain object",
1539                                              ldb_dn_get_linearized(dn));
1540                 talloc_free(local_ctx);
1541                 return LDB_ERR_CONSTRAINT_VIOLATION;
1542         }
1543 
1544         *parent_dn = talloc_steal(mem_ctx, res->msgs[0]->dn);
1545         talloc_free(local_ctx);
1546         return ret;
1547 }
1548 
1549 /*
1550   check that a password is sufficiently complex
1551 */
1552 static bool samdb_password_complexity_ok(const char *pass)
     /* [<][>][^][v][top][bottom][index][help] */
1553 {
1554         return check_password_quality(pass);
1555 }
1556 
1557 
1558 
1559 /*
1560   set the user password using plaintext, obeying any user or domain
1561   password restrictions
1562 
1563   note that this function doesn't actually store the result in the
1564   database, it just fills in the "mod" structure with ldb modify
1565   elements to setup the correct change when samdb_replace() is
1566   called. This allows the caller to combine the change with other
1567   changes (as is needed by some of the set user info levels)
1568 
1569   The caller should probably have a transaction wrapping this
1570 */
1571 NTSTATUS samdb_set_password(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1572                             struct ldb_dn *user_dn,
1573                             struct ldb_dn *domain_dn,
1574                             struct ldb_message *mod,
1575                             const DATA_BLOB *new_password,
1576                             struct samr_Password *lmNewHash, 
1577                             struct samr_Password *ntNewHash,
1578                             bool user_change,
1579                             enum samr_RejectReason *reject_reason,
1580                             struct samr_DomInfo1 **_dominfo)
1581 {
1582         const char * const user_attrs[] = { "userAccountControl", "lmPwdHistory", 
1583                                             "ntPwdHistory", 
1584                                             "dBCSPwd", "unicodePwd", 
1585                                             "objectSid", 
1586                                             "pwdLastSet", NULL };
1587         const char * const domain_attrs[] = { "pwdProperties", "pwdHistoryLength", 
1588                                               "maxPwdAge", "minPwdAge", 
1589                                               "minPwdLength", NULL };
1590         NTTIME pwdLastSet;
1591         int64_t minPwdAge;
1592         uint_t minPwdLength, pwdProperties, pwdHistoryLength;
1593         uint_t userAccountControl;
1594         struct samr_Password *sambaLMPwdHistory, *sambaNTPwdHistory, *lmPwdHash, *ntPwdHash;
1595         struct samr_Password local_lmNewHash, local_ntNewHash;
1596         int sambaLMPwdHistory_len, sambaNTPwdHistory_len;
1597         struct dom_sid *domain_sid;
1598         struct ldb_message **res;
1599         bool restrictions;
1600         int count;
1601         time_t now = time(NULL);
1602         NTTIME now_nt;
1603         int i;
1604 
1605         /* we need to know the time to compute password age */
1606         unix_to_nt_time(&now_nt, now);
1607 
1608         /* pull all the user parameters */
1609         count = gendb_search_dn(ctx, mem_ctx, user_dn, &res, user_attrs);
1610         if (count != 1) {
1611                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1612         }
1613         userAccountControl = samdb_result_uint(res[0],   "userAccountControl", 0);
1614         sambaLMPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1615                                                  "lmPwdHistory", &sambaLMPwdHistory);
1616         sambaNTPwdHistory_len =   samdb_result_hashes(mem_ctx, res[0], 
1617                                                  "ntPwdHistory", &sambaNTPwdHistory);
1618         lmPwdHash =          samdb_result_hash(mem_ctx, res[0],   "dBCSPwd");
1619         ntPwdHash =          samdb_result_hash(mem_ctx, res[0],   "unicodePwd");
1620         pwdLastSet =         samdb_result_uint64(res[0], "pwdLastSet", 0);
1621 
1622         /* Only non-trust accounts have restrictions (possibly this
1623          * test is the wrong way around, but I like to be restrictive
1624          * if possible */
1625         restrictions = !(userAccountControl & (UF_INTERDOMAIN_TRUST_ACCOUNT
1626                                                |UF_WORKSTATION_TRUST_ACCOUNT
1627                                                |UF_SERVER_TRUST_ACCOUNT)); 
1628 
1629         if (domain_dn) {
1630                 /* pull the domain parameters */
1631                 count = gendb_search_dn(ctx, mem_ctx, domain_dn, &res, domain_attrs);
1632                 if (count != 1) {
1633                         DEBUG(2, ("samdb_set_password: Domain DN %s is invalid, for user %s\n", 
1634                                   ldb_dn_get_linearized(domain_dn),
1635                                   ldb_dn_get_linearized(user_dn)));
1636                         return NT_STATUS_NO_SUCH_DOMAIN;
1637                 }
1638         } else {
1639                 /* work out the domain sid, and pull the domain from there */
1640                 domain_sid =         samdb_result_sid_prefix(mem_ctx, res[0], "objectSid");
1641                 if (domain_sid == NULL) {
1642                         return NT_STATUS_INTERNAL_DB_CORRUPTION;
1643                 }
1644 
1645                 count = gendb_search(ctx, mem_ctx, NULL, &res, domain_attrs, 
1646                                      "(objectSid=%s)", 
1647                                      ldap_encode_ndr_dom_sid(mem_ctx, domain_sid));
1648                 if (count != 1) {
1649                         DEBUG(2, ("samdb_set_password: Could not find domain to match SID: %s, for user %s\n", 
1650                                   dom_sid_string(mem_ctx, domain_sid),
1651                                   ldb_dn_get_linearized(user_dn)));
1652                         return NT_STATUS_NO_SUCH_DOMAIN;
1653                 }
1654         }
1655 
1656         pwdProperties =    samdb_result_uint(res[0],   "pwdProperties", 0);
1657         pwdHistoryLength = samdb_result_uint(res[0],   "pwdHistoryLength", 0);
1658         minPwdLength =     samdb_result_uint(res[0],   "minPwdLength", 0);
1659         minPwdAge =        samdb_result_int64(res[0],  "minPwdAge", 0);
1660 
1661         if (_dominfo) {
1662                 struct samr_DomInfo1 *dominfo;
1663                 /* on failure we need to fill in the reject reasons */
1664                 dominfo = talloc(mem_ctx, struct samr_DomInfo1);
1665                 if (dominfo == NULL) {
1666                         return NT_STATUS_NO_MEMORY;
1667                 }
1668                 dominfo->min_password_length     = minPwdLength;
1669                 dominfo->password_properties     = pwdProperties;
1670                 dominfo->password_history_length = pwdHistoryLength;
1671                 dominfo->max_password_age        = minPwdAge;
1672                 dominfo->min_password_age        = minPwdAge;
1673                 *_dominfo = dominfo;
1674         }
1675 
1676         if (restrictions && new_password) {
1677                 char *new_pass;
1678                 
1679                 /* check the various password restrictions */
1680                 if (restrictions && minPwdLength > utf16_len_n(new_password->data, new_password->length) / 2) {
1681                         if (reject_reason) {
1682                                 *reject_reason = SAMR_REJECT_TOO_SHORT;
1683                         }
1684                         return NT_STATUS_PASSWORD_RESTRICTION;
1685                 }
1686 
1687                 /* Create the NT hash */
1688                 mdfour(local_ntNewHash.hash, new_password->data, new_password->length);
1689                 
1690                 ntNewHash = &local_ntNewHash;
1691 
1692                 /* Only check complexity if we can convert it at all.  Assuming unconvertable passwords are 'strong' */
1693                 if (convert_string_talloc_convenience(mem_ctx, lp_iconv_convenience(ldb_get_opaque(ctx, "loadparm")), 
1694                                           CH_UTF16, CH_UNIX, 
1695                                           new_password->data, new_password->length, 
1696                                           (void **)&new_pass, NULL, false)) {
1697                         
1698                         
1699                         /* possibly check password complexity */
1700                         if (restrictions && pwdProperties & DOMAIN_PASSWORD_COMPLEX &&
1701                             !samdb_password_complexity_ok(new_pass)) {
1702                                 if (reject_reason) {
1703                                         *reject_reason = SAMR_REJECT_COMPLEXITY;
1704                                 }
1705                                 return NT_STATUS_PASSWORD_RESTRICTION;
1706                         }
1707                         
1708                         /* compute the new lm hashes (for checking history - case insenitivly!) */
1709                         if (E_deshash(new_pass, local_lmNewHash.hash)) {
1710                                 lmNewHash = &local_lmNewHash;
1711                         }
1712                         
1713                 }
1714         }
1715 
1716         if (restrictions && user_change) {
1717                 /* are all password changes disallowed? */
1718                 if (pwdProperties & DOMAIN_REFUSE_PASSWORD_CHANGE) {
1719                         if (reject_reason) {
1720                                 *reject_reason = SAMR_REJECT_OTHER;
1721                         }
1722                         return NT_STATUS_PASSWORD_RESTRICTION;
1723                 }
1724                 
1725                 /* can this user change password? */
1726                 if (userAccountControl & UF_PASSWD_CANT_CHANGE) {
1727                         if (reject_reason) {
1728                                 *reject_reason = SAMR_REJECT_OTHER;
1729                         }
1730                         return NT_STATUS_PASSWORD_RESTRICTION;
1731                 }
1732                 
1733                 /* yes, this is a minus. The ages are in negative 100nsec units! */
1734                 if (pwdLastSet - minPwdAge > now_nt) {
1735                         if (reject_reason) {
1736                                 *reject_reason = SAMR_REJECT_OTHER;
1737                         }
1738                         return NT_STATUS_PASSWORD_RESTRICTION;
1739                 }
1740 
1741                 /* check the immediately past password */
1742                 if (pwdHistoryLength > 0) {
1743                         if (lmNewHash && lmPwdHash && memcmp(lmNewHash->hash, lmPwdHash->hash, 16) == 0) {
1744                                 if (reject_reason) {
1745                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1746                                 }
1747                                 return NT_STATUS_PASSWORD_RESTRICTION;
1748                         }
1749                         if (ntNewHash && ntPwdHash && memcmp(ntNewHash->hash, ntPwdHash->hash, 16) == 0) {
1750                                 if (reject_reason) {
1751                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1752                                 }
1753                                 return NT_STATUS_PASSWORD_RESTRICTION;
1754                         }
1755                 }
1756                 
1757                 /* check the password history */
1758                 sambaLMPwdHistory_len = MIN(sambaLMPwdHistory_len, pwdHistoryLength);
1759                 sambaNTPwdHistory_len = MIN(sambaNTPwdHistory_len, pwdHistoryLength);
1760                 
1761                 for (i=0; lmNewHash && i<sambaLMPwdHistory_len;i++) {
1762                         if (memcmp(lmNewHash->hash, sambaLMPwdHistory[i].hash, 16) == 0) {
1763                                 if (reject_reason) {
1764                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1765                                 }
1766                                 return NT_STATUS_PASSWORD_RESTRICTION;
1767                         }
1768                 }
1769                 for (i=0; ntNewHash && i<sambaNTPwdHistory_len;i++) {
1770                         if (memcmp(ntNewHash->hash, sambaNTPwdHistory[i].hash, 16) == 0) {
1771                                 if (reject_reason) {
1772                                         *reject_reason = SAMR_REJECT_IN_HISTORY;
1773                                 }
1774                                 return NT_STATUS_PASSWORD_RESTRICTION;
1775                         }
1776                 }
1777         }
1778 
1779 #define CHECK_RET(x) do { if (x != 0) return NT_STATUS_NO_MEMORY; } while(0)
1780 
1781         /* the password is acceptable. Start forming the new fields */
1782         if (new_password) {
1783                 /* if we know the cleartext UTF16 password, then set it.
1784                  * Modules in ldb will set all the appropriate
1785                  * hashes */
1786                 CHECK_RET(ldb_msg_add_value(mod, "clearTextPassword", new_password, NULL));
1787         } else {
1788                 /* We don't have the cleartext, so delete the old one
1789                  * and set what we have of the hashes */
1790                 CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "clearTextPassword"));
1791 
1792                 if (lmNewHash) {
1793                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "dBCSPwd", lmNewHash));
1794                 } else {
1795                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "dBCSPwd"));
1796                 }
1797                 
1798                 if (ntNewHash) {
1799                         CHECK_RET(samdb_msg_add_hash(ctx, mem_ctx, mod, "unicodePwd", ntNewHash));
1800                 } else {
1801                         CHECK_RET(samdb_msg_add_delete(ctx, mem_ctx, mod, "unicodePwd"));
1802                 }
1803         }
1804 
1805         return NT_STATUS_OK;
1806 }
1807 
1808 
1809 /*
1810   set the user password using plaintext, obeying any user or domain
1811   password restrictions
1812 
1813   This wrapper function takes a SID as input, rather than a user DN,
1814   and actually performs the password change
1815 
1816 */
1817 NTSTATUS samdb_set_password_sid(struct ldb_context *ctx, TALLOC_CTX *mem_ctx,
     /* [<][>][^][v][top][bottom][index][help] */
1818                                 const struct dom_sid *user_sid,
1819                                 const DATA_BLOB *new_pass,
1820                                 struct samr_Password *lmNewHash, 
1821                                 struct samr_Password *ntNewHash,
1822                                 bool user_change,
1823                                 enum samr_RejectReason *reject_reason,
1824                                 struct samr_DomInfo1 **_dominfo) 
1825 {
1826         NTSTATUS nt_status;
1827         struct ldb_dn *user_dn;
1828         struct ldb_message *msg;
1829         int ret;
1830 
1831         ret = ldb_transaction_start(ctx);
1832         if (ret) {
1833                 DEBUG(1, ("Failed to start transaction: %s\n", ldb_errstring(ctx)));
1834                 return NT_STATUS_TRANSACTION_ABORTED;
1835         }
1836 
1837         user_dn = samdb_search_dn(ctx, mem_ctx, NULL, 
1838                                   "(&(objectSid=%s)(objectClass=user))", 
1839                                   ldap_encode_ndr_dom_sid(mem_ctx, user_sid));
1840         if (!user_dn) {
1841                 ldb_transaction_cancel(ctx);
1842                 DEBUG(3, ("samdb_set_password_sid: SID %s not found in samdb, returning NO_SUCH_USER\n",
1843                           dom_sid_string(mem_ctx, user_sid)));
1844                 return NT_STATUS_NO_SUCH_USER;
1845         }
1846 
1847         msg = ldb_msg_new(mem_ctx);
1848         if (msg == NULL) {
1849                 ldb_transaction_cancel(ctx);
1850                 return NT_STATUS_NO_MEMORY;
1851         }
1852 
1853         msg->dn = ldb_dn_copy(msg, user_dn);
1854         if (!msg->dn) {
1855                 ldb_transaction_cancel(ctx);
1856                 return NT_STATUS_NO_MEMORY;
1857         }
1858 
1859         nt_status = samdb_set_password(ctx, mem_ctx,
1860                                        user_dn, NULL,
1861                                        msg, new_pass, 
1862                                        lmNewHash, ntNewHash,
1863                                        user_change, /* This is a password set, not change */
1864                                        reject_reason, _dominfo);
1865         if (!NT_STATUS_IS_OK(nt_status)) {
1866                 ldb_transaction_cancel(ctx);
1867                 return nt_status;
1868         }
1869         
1870         /* modify the samdb record */
1871         ret = samdb_replace(ctx, mem_ctx, msg);
1872         if (ret != 0) {
1873                 ldb_transaction_cancel(ctx);
1874                 return NT_STATUS_ACCESS_DENIED;
1875         }
1876 
1877         ret = ldb_transaction_commit(ctx);
1878         if (ret != 0) {
1879                 DEBUG(0,("Failed to commit transaction to change password on %s: %s\n",
1880                          ldb_dn_get_linearized(msg->dn),
1881                          ldb_errstring(ctx)));
1882                 return NT_STATUS_TRANSACTION_ABORTED;
1883         }
1884         return NT_STATUS_OK;
1885 }
1886 
1887 
1888 
1889 NTSTATUS samdb_create_foreign_security_principal(struct ldb_context *sam_ctx, TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
1890                                                  struct dom_sid *sid, struct ldb_dn **ret_dn) 
1891 {
1892         struct ldb_message *msg;
1893         struct ldb_dn *basedn;
1894         const char *sidstr;
1895         int ret;
1896         
1897         sidstr = dom_sid_string(mem_ctx, sid);
1898         NT_STATUS_HAVE_NO_MEMORY(sidstr);
1899         
1900         /* We might have to create a ForeignSecurityPrincipal, even if this user
1901          * is in our own domain */
1902         
1903         msg = ldb_msg_new(mem_ctx);
1904         if (msg == NULL) {
1905                 return NT_STATUS_NO_MEMORY;
1906         }
1907         
1908         /* TODO: Hmmm. This feels wrong. How do I find the base dn to
1909          * put the ForeignSecurityPrincipals? d_state->domain_dn does
1910          * not work, this is wrong for the Builtin domain, there's no
1911          * cn=For...,cn=Builtin,dc={BASEDN}.  -- vl
1912          */
1913         
1914         basedn = samdb_search_dn(sam_ctx, mem_ctx, NULL,
1915                                  "(&(objectClass=container)(cn=ForeignSecurityPrincipals))");
1916         
1917         if (basedn == NULL) {
1918                 DEBUG(0, ("Failed to find DN for "
1919                           "ForeignSecurityPrincipal container\n"));
1920                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1921         }
1922         
1923         /* add core elements to the ldb_message for the alias */
1924         msg->dn = ldb_dn_copy(mem_ctx, basedn);
1925         if ( ! ldb_dn_add_child_fmt(msg->dn, "CN=%s", sidstr))
1926                 return NT_STATUS_NO_MEMORY;
1927         
1928         samdb_msg_add_string(sam_ctx, mem_ctx, msg,
1929                              "objectClass",
1930                              "foreignSecurityPrincipal");
1931         
1932         /* create the alias */
1933         ret = ldb_add(sam_ctx, msg);
1934         if (ret != 0) {
1935                 DEBUG(0,("Failed to create foreignSecurityPrincipal "
1936                          "record %s: %s\n", 
1937                          ldb_dn_get_linearized(msg->dn),
1938                          ldb_errstring(sam_ctx)));
1939                 return NT_STATUS_INTERNAL_DB_CORRUPTION;
1940         }
1941         *ret_dn = msg->dn;
1942         return NT_STATUS_OK;
1943 }
1944 
1945 
1946 /*
1947   Find the DN of a domain, assuming it to be a dotted.dns name
1948 */
1949 
1950 struct ldb_dn *samdb_dns_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const char *dns_domain) 
     /* [<][>][^][v][top][bottom][index][help] */
1951 {
1952         int i;
1953         TALLOC_CTX *tmp_ctx = talloc_new(mem_ctx);
1954         const char *binary_encoded;
1955         const char **split_realm;
1956         struct ldb_dn *dn;
1957         
1958         if (!tmp_ctx) {
1959                 return NULL;
1960         }
1961         
1962         split_realm = (const char **)str_list_make(tmp_ctx, dns_domain, ".");
1963         if (!split_realm) {
1964                 talloc_free(tmp_ctx);
1965                 return NULL;
1966         }
1967         dn = ldb_dn_new(mem_ctx, ldb, NULL);
1968         for (i=0; split_realm[i]; i++) {
1969                 binary_encoded = ldb_binary_encode_string(tmp_ctx, split_realm[i]);
1970                 if (!ldb_dn_add_base_fmt(dn, "dc=%s", binary_encoded)) {
1971                         DEBUG(2, ("Failed to add dc=%s element to DN %s\n",
1972                                   binary_encoded, ldb_dn_get_linearized(dn)));
1973                         talloc_free(tmp_ctx);
1974                         return NULL;
1975                 }
1976         }
1977         if (!ldb_dn_validate(dn)) {
1978                 DEBUG(2, ("Failed to validated DN %s\n",
1979                           ldb_dn_get_linearized(dn)));
1980                 return NULL;
1981         }
1982         return dn;
1983 }
1984 /*
1985   Find the DN of a domain, be it the netbios or DNS name 
1986 */
1987 
1988 struct ldb_dn *samdb_domain_to_dn(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, 
     /* [<][>][^][v][top][bottom][index][help] */
1989                                   const char *domain_name) 
1990 {
1991         const char * const domain_ref_attrs[] = {
1992                 "ncName", NULL
1993         };
1994         const char * const domain_ref2_attrs[] = {
1995                 NULL
1996         };
1997         struct ldb_result *res_domain_ref;
1998         char *escaped_domain = ldb_binary_encode_string(mem_ctx, domain_name);
1999         /* find the domain's DN */
2000         int ret_domain = ldb_search(ldb, mem_ctx,
2001                                             &res_domain_ref, 
2002                                             samdb_partitions_dn(ldb, mem_ctx), 
2003                                             LDB_SCOPE_ONELEVEL, 
2004                                             domain_ref_attrs,
2005                                             "(&(nETBIOSName=%s)(objectclass=crossRef))", 
2006                                             escaped_domain);
2007         if (ret_domain != 0) {
2008                 return NULL;
2009         }
2010         
2011         if (res_domain_ref->count == 0) {
2012                 ret_domain = ldb_search(ldb, mem_ctx,
2013                                                 &res_domain_ref, 
2014                                                 samdb_dns_domain_to_dn(ldb, mem_ctx, domain_name),
2015                                                 LDB_SCOPE_BASE,
2016                                                 domain_ref2_attrs,
2017                                                 "(objectclass=domain)");
2018                 if (ret_domain != 0) {
2019                         return NULL;
2020                 }
2021         
2022                 if (res_domain_ref->count == 1) {
2023                         return res_domain_ref->msgs[0]->dn;
2024                 }
2025                 return NULL;
2026         }
2027         
2028         if (res_domain_ref->count > 1) {
2029                 DEBUG(0,("Found %d records matching domain [%s]\n", 
2030                          ret_domain, domain_name));
2031                 return NULL;
2032         }
2033         
2034         return samdb_result_dn(ldb, mem_ctx, res_domain_ref->msgs[0], "nCName", NULL);
2035 
2036 }

/* [<][>][^][v][top][bottom][index][help] */