diff options
Diffstat (limited to 'source4')
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/objectclass_attrs.c | 9 | ||||
-rw-r--r-- | source4/dsdb/samdb/ldb_modules/repl_meta_data.c | 205 | ||||
-rw-r--r-- | source4/dsdb/samdb/samdb.h | 6 | ||||
-rw-r--r-- | source4/lib/ldb/pyldb.c | 43 | ||||
-rwxr-xr-x | source4/scripting/bin/upgradeprovision | 583 | ||||
-rwxr-xr-x | source4/scripting/devel/chgtdcpass | 63 | ||||
-rw-r--r-- | source4/scripting/python/samba/provision.py | 38 | ||||
-rw-r--r-- | source4/scripting/python/samba/samdb.py | 103 | ||||
-rw-r--r-- | source4/scripting/python/samba/tests/dsdb.py | 113 | ||||
-rw-r--r-- | source4/scripting/python/samba/tests/upgradeprovisionneeddc.py | 26 | ||||
-rwxr-xr-x | source4/scripting/python/samba/upgradehelpers.py | 85 | ||||
-rwxr-xr-x | source4/selftest/tests.sh | 11 | ||||
-rw-r--r-- | source4/setup/schema_samba4.ldif | 1 | ||||
-rwxr-xr-x | source4/utils/tests/test_net.sh | 2 |
14 files changed, 955 insertions, 333 deletions
diff --git a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c index 6cfecc0d72..b9436e3a04 100644 --- a/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c +++ b/source4/dsdb/samdb/ldb_modules/objectclass_attrs.c @@ -153,6 +153,12 @@ static int attr_handler(struct oc_context *ac) return ldb_next_request(ac->module, child_req); } +/* + these are attributes which are left over from old ways of doing + things in ldb, and are harmless + */ +static const char *harmless_attrs[] = { "parentGUID", NULL }; + static int attr_handler2(struct oc_context *ac) { struct ldb_context *ldb; @@ -219,6 +225,9 @@ static int attr_handler2(struct oc_context *ac) found = str_list_check(may_contain, attr->lDAPDisplayName); } if (!found) { + found = str_list_check(harmless_attrs, attr->lDAPDisplayName); + } + if (!found) { ldb_asprintf_errstring(ldb, "objectclass_attrs: attribute '%s' on entry '%s' does not exist in the specified objectclasses!", msg->elements[i].name, ldb_dn_get_linearized(msg->dn)); diff --git a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c index 90af17f7ec..2205be07c1 100644 --- a/source4/dsdb/samdb/ldb_modules/repl_meta_data.c +++ b/source4/dsdb/samdb/ldb_modules/repl_meta_data.c @@ -5,6 +5,7 @@ Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005 Copyright (C) Andrew Tridgell 2005 Copyright (C) Stefan Metzmacher <metze@samba.org> 2007 + Copyright (C) Matthieu Patou <mat@samba.org> 2010 This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -1073,6 +1074,20 @@ static int replmd_update_rpmd_element(struct ldb_context *ldb, return LDB_SUCCESS; } +static uint64_t find_max_local_usn(struct replPropertyMetaDataBlob omd) +{ + uint32_t count = omd.ctr.ctr1.count; + uint64_t max = 0; + uint32_t i; + for (i=0; i < count; i++) { + struct replPropertyMetaData1 m = omd.ctr.ctr1.array[i]; + if (max < m.local_usn) { + max = m.local_usn; + } + } + return max; +} + /* * update the replPropertyMetaData object each time we modify an * object. This is needed for DRS replication, as the merge on the @@ -1093,11 +1108,12 @@ static int replmd_update_rpmd(struct ldb_module *module, const struct GUID *our_invocation_id; int ret; const char *attrs[] = { "replPropertyMetaData", "*", NULL }; + const char *attrs2[] = { "uSNChanged", "objectClass", NULL }; struct ldb_result *res; struct ldb_context *ldb; struct ldb_message_element *objectclass_el; enum urgent_situation situation; - bool rodc; + bool rodc, rmd_is_provided; ldb = ldb_module_get_ctx(module); @@ -1111,21 +1127,10 @@ static int replmd_update_rpmd(struct ldb_module *module, unix_to_nt_time(&now, t); - /* search for the existing replPropertyMetaDataBlob. We need - * to use REVEAL and ask for DNs in storage format to support - * the check for values being the same in - * replmd_update_rpmd_element() - */ - ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs, - DSDB_FLAG_NEXT_MODULE | - DSDB_SEARCH_SHOW_DELETED | - DSDB_SEARCH_SHOW_EXTENDED_DN | - DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | - DSDB_SEARCH_REVEAL_INTERNALS); - if (ret != LDB_SUCCESS || res->count != 1) { - DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n", - ldb_dn_get_linearized(msg->dn))); - return LDB_ERR_OPERATIONS_ERROR; + if (ldb_request_get_control(req, DSDB_CONTROL_CHANGEREPLMETADATA_OID)) { + rmd_is_provided = true; + } else { + rmd_is_provided = false; } /* if isDeleted is present and is TRUE, then we consider we are deleting, @@ -1136,62 +1141,140 @@ static int replmd_update_rpmd(struct ldb_module *module, situation = REPL_URGENT_ON_UPDATE; } - objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass"); - if (is_urgent && replmd_check_urgent_objectclass(objectclass_el, - situation)) { - *is_urgent = true; - } + if (rmd_is_provided) { + /* In this case the change_replmetadata control was supplied */ + /* We check that it's the only attribute that is provided + * (it's a rare case so it's better to keep the code simplier) + * We also check that the highest local_usn is bigger than + * uSNChanged. */ + uint64_t db_seq; + if( msg->num_elements != 1 || + strncmp(msg->elements[0].name, + "replPropertyMetaData", 20) ) { + DEBUG(0,(__location__ ": changereplmetada control called without "\ + "a specified replPropertyMetaData attribute or with others\n")); + return LDB_ERR_OPERATIONS_ERROR; + } + if (situation == REPL_URGENT_ON_DELETE) { + DEBUG(0,(__location__ ": changereplmetada control can't be called when deleting an object\n")); + return LDB_ERR_OPERATIONS_ERROR; + } + omd_value = ldb_msg_find_ldb_val(msg, "replPropertyMetaData"); + if (!omd_value) { + DEBUG(0,(__location__ ": replPropertyMetaData was not specified for Object %s\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd, + (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + *seq_num = find_max_local_usn(omd); - omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData"); - if (!omd_value) { - DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n", - ldb_dn_get_linearized(msg->dn))); - return LDB_ERR_OPERATIONS_ERROR; - } + ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs2, + DSDB_FLAG_NEXT_MODULE | + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_EXTENDED_DN | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS); - ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd, - (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob); - if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { - DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n", - ldb_dn_get_linearized(msg->dn))); - return LDB_ERR_OPERATIONS_ERROR; - } + if (ret != LDB_SUCCESS || res->count != 1) { + DEBUG(0,(__location__ ": Object %s failed to find uSNChanged\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } - if (omd.version != 1) { - DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n", - omd.version, ldb_dn_get_linearized(msg->dn))); - return LDB_ERR_OPERATIONS_ERROR; - } + objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass"); + if (is_urgent && replmd_check_urgent_objectclass(objectclass_el, + situation)) { + *is_urgent = true; + } - /*we have elements that will be modified*/ - if (msg->num_elements > 0) { - /*if we are RODC and this is a DRSR update then its ok*/ - if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) { - ret = samdb_rodc(ldb, &rodc); - if (ret != LDB_SUCCESS) { - DEBUG(4, (__location__ ": unable to tell if we are an RODC\n")); - } else if (rodc) { - ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n"); - return LDB_ERR_REFERRAL; - } + db_seq = ldb_msg_find_attr_as_uint64(res->msgs[0], "uSNChanged", 0); + if (*seq_num <= db_seq) { + DEBUG(0,(__location__ ": changereplmetada control provided but max(local_usn)"\ + " is less or equal to uSNChanged (max = %lld uSNChanged = %lld)\n", + *seq_num, db_seq)); + return LDB_ERR_OPERATIONS_ERROR; } - } - for (i=0; i<msg->num_elements; i++) { - struct ldb_message_element *old_el; - old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name); - ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num, - our_invocation_id, now); - if (ret != LDB_SUCCESS) { - return ret; + } else { + /* search for the existing replPropertyMetaDataBlob. We need + * to use REVEAL and ask for DNs in storage format to support + * the check for values being the same in + * replmd_update_rpmd_element() + */ + ret = dsdb_module_search_dn(module, msg, &res, msg->dn, attrs, + DSDB_FLAG_NEXT_MODULE | + DSDB_SEARCH_SHOW_DELETED | + DSDB_SEARCH_SHOW_EXTENDED_DN | + DSDB_SEARCH_SHOW_DN_IN_STORAGE_FORMAT | + DSDB_SEARCH_REVEAL_INTERNALS); + if (ret != LDB_SUCCESS || res->count != 1) { + DEBUG(0,(__location__ ": Object %s failed to find replPropertyMetaData\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; } - if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) { - *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]); + objectclass_el = ldb_msg_find_element(res->msgs[0], "objectClass"); + if (is_urgent && replmd_check_urgent_objectclass(objectclass_el, + situation)) { + *is_urgent = true; } - } + omd_value = ldb_msg_find_ldb_val(res->msgs[0], "replPropertyMetaData"); + if (!omd_value) { + DEBUG(0,(__location__ ": Object %s does not have a replPropertyMetaData attribute\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + ndr_err = ndr_pull_struct_blob(omd_value, msg, &omd, + (ndr_pull_flags_fn_t)ndr_pull_replPropertyMetaDataBlob); + if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { + DEBUG(0,(__location__ ": Failed to parse replPropertyMetaData for %s\n", + ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + + if (omd.version != 1) { + DEBUG(0,(__location__ ": bad version %u in replPropertyMetaData for %s\n", + omd.version, ldb_dn_get_linearized(msg->dn))); + return LDB_ERR_OPERATIONS_ERROR; + } + + /*we have elements that will be modified*/ + if (msg->num_elements > 0) { + /*if we are RODC and this is a DRSR update then its ok*/ + if (!ldb_request_get_control(req, DSDB_CONTROL_REPLICATED_UPDATE_OID)) { + ret = samdb_rodc(ldb, &rodc); + if (ret != LDB_SUCCESS) { + DEBUG(4, (__location__ ": unable to tell if we are an RODC\n")); + } else if (rodc) { + ldb_asprintf_errstring(ldb, "RODC modify is forbidden\n"); + return LDB_ERR_REFERRAL; + } + } + } + + for (i=0; i<msg->num_elements; i++) { + struct ldb_message_element *old_el; + old_el = ldb_msg_find_element(res->msgs[0], msg->elements[i].name); + ret = replmd_update_rpmd_element(ldb, msg, &msg->elements[i], old_el, &omd, schema, seq_num, + our_invocation_id, now); + if (ret != LDB_SUCCESS) { + return ret; + } + + if (is_urgent && !*is_urgent && (situation == REPL_URGENT_ON_UPDATE)) { + *is_urgent = replmd_check_urgent_attribute(&msg->elements[i]); + } + + } + } /* * replmd_update_rpmd_element has done an update if the * seq_num is set diff --git a/source4/dsdb/samdb/samdb.h b/source4/dsdb/samdb/samdb.h index 8b45cd0180..75aae7f108 100644 --- a/source4/dsdb/samdb/samdb.h +++ b/source4/dsdb/samdb/samdb.h @@ -92,6 +92,12 @@ struct dsdb_control_password_change_status { */ #define DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID "1.3.6.1.4.1.7165.4.3.12" +/** + OID used to allow the replacement of replPropertyMetaData. + It is used when the current replmetadata needs to be edited. +*/ +#define DSDB_CONTROL_CHANGEREPLMETADATA_OID "1.3.6.1.4.1.7165.4.3.14" + #define DSDB_EXTENDED_REPLICATED_OBJECTS_OID "1.3.6.1.4.1.7165.4.4.1" struct dsdb_extended_replicated_object { struct ldb_message *msg; diff --git a/source4/lib/ldb/pyldb.c b/source4/lib/ldb/pyldb.c index b886a4b81c..f27ab3dd95 100644 --- a/source4/lib/ldb/pyldb.c +++ b/source4/lib/ldb/pyldb.c @@ -1249,6 +1249,26 @@ static PyObject *py_ldb_modules(PyLdbObject *self) return ret; } +static PyObject *py_ldb_sequence_number(PyLdbObject *self, PyObject *args) +{ + struct ldb_context *ldb = PyLdb_AsLdbContext(self); + int type, ret; + uint64_t value; + + /* type "int" rather than "enum" for "scope" is intentional */ + if (!PyArg_ParseTuple(args, "i", &type)) + return NULL; + + /* FIXME: More interpretation */ + + ret = ldb_sequence_number(ldb, type, &value); + + if (ret != LDB_SUCCESS) { + PyErr_LDB_ERROR_IS_ERR_RAISE(PyExc_LdbError, ret, ldb); + return NULL; + } + return PyLong_FromLongLong(value); +} static PyMethodDef py_ldb_methods[] = { { "set_debug", (PyCFunction)py_ldb_set_debug, METH_VARARGS, "S.set_debug(callback) -> None\n" @@ -1335,6 +1355,9 @@ static PyMethodDef py_ldb_methods[] = { { "modules", (PyCFunction)py_ldb_modules, METH_NOARGS, "S.modules() -> list\n" "Return the list of modules on this LDB connection " }, + { "sequence_number", (PyCFunction)py_ldb_sequence_number, METH_VARARGS, + "S.sequence_number(type) -> value\n" + "Return the value of the sequence according to the requested type" }, { NULL }, }; @@ -1635,9 +1658,14 @@ struct ldb_message_element *PyObject_AsMessageElement(TALLOC_CTX *mem_ctx, { struct ldb_message_element *me; - if (PyLdbMessageElement_Check(set_obj)) - return talloc_reference(mem_ctx, - PyLdbMessageElement_AsMessageElement(set_obj)); + if (PyLdbMessageElement_Check(set_obj)) { + PyLdbMessageElementObject *set_obj_as_me = (PyLdbMessageElementObject *)set_obj; + /* We have to talloc_reference() the memory context, not the pointer which may not actually be it's own context */ + if (talloc_reference(mem_ctx, set_obj_as_me->mem_ctx)) { + return PyLdbMessageElement_AsMessageElement(set_obj); + } + return NULL; + } me = talloc(mem_ctx, struct ldb_message_element); @@ -1941,7 +1969,7 @@ static PyObject *py_ldb_msg_getitem_helper(PyLdbMessageObject *self, PyObject *p if (el == NULL) { return NULL; } - return (PyObject *)PyLdbMessageElement_FromMessageElement(el, msg); + return (PyObject *)PyLdbMessageElement_FromMessageElement(el, msg->elements); } static PyObject *py_ldb_msg_getitem(PyLdbMessageObject *self, PyObject *py_name) @@ -1980,7 +2008,7 @@ static PyObject *py_ldb_msg_items(PyLdbMessageObject *self) j++; } for (i = 0; i < msg->num_elements; i++, j++) { - PyList_SetItem(l, j, Py_BuildValue("(sO)", msg->elements[i].name, PyLdbMessageElement_FromMessageElement(&msg->elements[i], self->msg))); + PyList_SetItem(l, j, Py_BuildValue("(sO)", msg->elements[i].name, PyLdbMessageElement_FromMessageElement(&msg->elements[i], msg->elements))); } return l; } @@ -2018,7 +2046,7 @@ static int py_ldb_msg_setitem(PyLdbMessageObject *self, PyObject *name, PyObject ldb_msg_remove_attr(self->msg, attr_name); } else { struct ldb_message_element *el = PyObject_AsMessageElement(self->msg, - value, 0, attr_name); + value, 0, attr_name); if (el == NULL) return -1; ldb_msg_remove_attr(PyLdbMessage_AsMessage(self), attr_name); @@ -2594,6 +2622,9 @@ void initldb(void) if (m == NULL) return; + PyModule_AddObject(m, "SEQ_HIGHEST_SEQ", PyInt_FromLong(LDB_SEQ_HIGHEST_SEQ)); + PyModule_AddObject(m, "SEQ_HIGHEST_TIMESTAMP", PyInt_FromLong(LDB_SEQ_HIGHEST_TIMESTAMP)); + PyModule_AddObject(m, "SEQ_NEXT", PyInt_FromLong(LDB_SEQ_NEXT)); PyModule_AddObject(m, "SCOPE_DEFAULT", PyInt_FromLong(LDB_SCOPE_DEFAULT)); PyModule_AddObject(m, "SCOPE_BASE", PyInt_FromLong(LDB_SCOPE_BASE)); PyModule_AddObject(m, "SCOPE_ONELEVEL", PyInt_FromLong(LDB_SCOPE_ONELEVEL)); diff --git a/source4/scripting/bin/upgradeprovision b/source4/scripting/bin/upgradeprovision index 48c4ce63b8..deb50e36fb 100755 --- a/source4/scripting/bin/upgradeprovision +++ b/source4/scripting/bin/upgradeprovision @@ -43,20 +43,22 @@ from ldb import (SCOPE_SUBTREE, SCOPE_BASE, MessageElement, Message, Dn) from samba import param from samba.provision import (find_setup_dir, get_domain_descriptor, - get_config_descriptor, secretsdb_self_join, + get_config_descriptor, ProvisioningError, get_last_provision_usn, get_max_usn, update_provision_usn) from samba.schema import get_linked_attributes, Schema, get_schema_descriptor -from samba.dcerpc import security, drsblobs +from samba.dcerpc import security, drsblobs, xattr from samba.ndr import ndr_unpack -from samba.dcerpc.misc import SEC_CHAN_BDC from samba.upgradehelpers import (dn_sort, get_paths, newprovision, find_provision_key_parameters, get_ldbs, usn_in_range, identic_rename, get_diff_sddls, update_secrets, CHANGE, ERROR, SIMPLE, CHANGEALL, GUESS, CHANGESD, PROVISION, updateOEMInfo, getOEMInfo, update_gpo, - delta_update_basesamdb, update_policyids) + delta_update_basesamdb, update_policyids, + update_machine_account_password, + search_constructed_attrs_stored, + increment_calculated_keyversion_number) replace=2**FLAG_MOD_REPLACE add=2**FLAG_MOD_ADD @@ -103,7 +105,9 @@ hashOverwrittenAtt = { "prefixMap": replace, "systemMayContain": replace, "wellKnownObjects":replace, "privilege":never, "defaultSecurityDescriptor": replace, "rIDAvailablePool": never, - "defaultSecurityDescriptor": replace + add } + "defaultSecurityDescriptor": replace + add, + "isMemberOfPartialAttributeSet": delete, + "attributeDisplayNames": replace + add} backlinked = [] @@ -285,7 +289,7 @@ def print_provision_key_parameters(names): message(GUESS, "domainlevel :" + str(names.domainlevel)) -def handle_special_case(att, delta, new, old, usn): +def handle_special_case(att, delta, new, old, usn, basedn, aldb): """Define more complicate update rules for some attributes :param att: The attribute to be updated @@ -294,6 +298,8 @@ def handle_special_case(att, delta, new, old, usn): :param new: The reference object :param old: The Updated object :param usn: The highest usn modified by a previous (upgrade)provision + :param basedn: The base DN of the provision + :param aldb: An ldb object used to build DN :return: True to indicate that the attribute should be kept, False for discarding it""" @@ -302,6 +308,23 @@ def handle_special_case(att, delta, new, old, usn): # highest usn as otherwise the replPropertyMetaData will guide us more # correctly if usn is None: + if (att == "sPNMappings" and flag == FLAG_MOD_REPLACE and + ldb.Dn(aldb, "CN=Directory Service,CN=Windows NT," + "CN=Services,CN=Configuration,%s" % basedn) + == old[0].dn): + return True + if (att == "userAccountControl" and flag == FLAG_MOD_REPLACE and + ldb.Dn(aldb, "CN=Administrator,CN=Users,%s" % basedn) + == old[0].dn): + message(SIMPLE, "We suggest that you change the userAccountControl" + " for user Administrator from value %d to %d" % + (int(str(old[0][att])), int(str(new[0][att])))) + return False + if (att == "minPwdAge" and flag == FLAG_MOD_REPLACE): + if (long(str(old[0][att])) == 0): + delta[att] = MessageElement(new[0][att], FLAG_MOD_REPLACE, att) + return True + if (att == "member" and flag == FLAG_MOD_REPLACE): hash = {} newval = [] @@ -320,7 +343,7 @@ def handle_special_case(att, delta, new, old, usn): delta.remove(att) return True - if (att in ("gPLink", "gPCFileSysPath") and + if (att in ("gPLink", "gPCFileSysPath") and flag == FLAG_MOD_REPLACE and str(new[0].dn).lower() == str(old[0].dn).lower()): delta.remove(att) @@ -516,30 +539,40 @@ def add_missing_object(ref_samdb, samdb, dn, names, basedn, hash, index): empty = Message() delta = samdb.msg_diff(empty, reference[0]) delta.dn - if delta.get("objectSid"): - sid = str(ndr_unpack(security.dom_sid, str(reference[0]["objectSid"]))) - m = re.match(r".*-(\d+)$", sid) - if m and int(m.group(1))>999: - delta.remove("objectSid") - for att in hashAttrNotCopied.keys(): - delta.remove(att) - for att in backlinked: - delta.remove(att) - depend_on_yettobecreated = None - for att in dn_syntax_att: - depend_on_yet_tobecreated = check_dn_nottobecreated(hash, index, - delta.get(str(att))) - if depend_on_yet_tobecreated is not None: - message(CHANGE, "Object %s depends on %s in attribute %s," - "delaying the creation" % (dn, - depend_on_yet_tobecreated, att)) - return False + skip = False + try: + if str(reference[0].get("cn")) == "RID Set": + for klass in reference[0].get("objectClass"): + if str(klass).lower == "ridset": + skip = True + finally: + if delta.get("objectSid"): + sid = str(ndr_unpack(security.dom_sid, str(reference[0]["objectSid"]))) + m = re.match(r".*-(\d+)$", sid) + if m and int(m.group(1))>999: + delta.remove("objectSid") + for att in hashAttrNotCopied.keys(): + delta.remove(att) + for att in backlinked: + delta.remove(att) + depend_on_yettobecreated = None + for att in dn_syntax_att: + depend_on_yet_tobecreated = check_dn_nottobecreated(hash, index, + delta.get(str(att))) + if depend_on_yet_tobecreated is not None: + message(CHANGE, "Object %s depends on %s in attribute %s," + "delaying the creation" % (dn, + depend_on_yet_tobecreated, att)) + return False - delta.dn = dn - message(CHANGE,"Object %s will be added" % dn) - samdb.add(delta, ["relax:0"]) + delta.dn = dn + if not skip: + message(CHANGE,"Object %s will be added" % dn) + samdb.add(delta, ["relax:0"]) + else: + message(CHANGE,"Object %s was skipped" % dn) - return True + return True def gen_dn_index_hash(listMissing): """Generate a hash associating the DN to its creation order @@ -813,7 +846,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): # idea to change it delta.remove(att) continue - if handle_special_case(att, delta, reference, current, usns): + if handle_special_case(att, delta, reference, current, usns, basedn, samdb): # This attribute is "complicated" to handle and handling # was done in handle_special_case continue @@ -827,16 +860,16 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): if attrUSN == -1: # This attribute was last modified by another DC forget # about it - message(CHANGE, "%sAttribute: %s has been" + message(CHANGE, "%sAttribute: %s has been" "created/modified/deleted by another DC," " do nothing" % (txt, att )) txt = "" delta.remove(att) continue elif not usn_in_range(int(attrUSN), usns): - message(CHANGE, "%sAttribute: %s has been" - "created/modified/deleted not during a" - " provision or upgradeprovision: current" + message(CHANGE, "%sAttribute: %s has been" + "created/modified/deleted not during a" + " provision or upgradeprovision: current" " usn %d , do nothing" % (txt, att, attrUSN)) txt = "" delta.remove(att) @@ -845,13 +878,13 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): if att == "defaultSecurityDescriptor": defSDmodified = True if attrUSN: - message(CHANGE, "%sAttribute: %s will be modified" - "/deleted it was last modified" - "during a provision, current usn:" + message(CHANGE, "%sAttribute: %s will be modified" + "/deleted it was last modified" + "during a provision, current usn:" "%d" % (txt, att, attrUSN)) txt = "" else: - message(CHANGE, "%sAttribute: %s will be added because" + message(CHANGE, "%sAttribute: %s will be added because" " it hasn't existed before " % (txt, att)) txt = "" continue @@ -871,7 +904,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): if not hashOverwrittenAtt.has_key(att): if msgElt.flags() != FLAG_MOD_ADD: if not handle_special_case(att, delta, reference, current, - usns): + usns, basedn, samdb): if opts.debugchange or opts.debugall: try: dump_denied_change(dn, att, @@ -893,7 +926,7 @@ def update_present(ref_samdb, samdb, basedn, listPresent, usns, invocationid): delta.dn = dn if len(delta.items()) >1: attributes=", ".join(delta.keys()) - message(CHANGE, "%s is different from the reference one, changed" + message(CHANGE, "%s is different from the reference one, changed" " attributes: %s\n" % (dn, attributes)) changed += 1 samdb.modify(delta) @@ -1002,6 +1035,7 @@ def check_updated_sd(ref_sam, cur_sam, names): str(reference[i]["nTSecurityDescriptor"])) hash[str(reference[i]["dn"]).lower()] = refsd.as_sddl(names.domainsid) + for i in range(0, len(current)): key = str(current[i]["dn"]).lower() if hash.has_key(key): @@ -1073,7 +1107,7 @@ def rebuild_sd(samdb, names): controls=["search_options:1:2"]) for obj in res: if not (str(obj["dn"]) == str(names.rootdn) or - str(obj["dn"]) == str(names.configdn) or + str(obj["dn"]) == str(names.configdn) or str(obj["dn"]) == str(names.schemadn)): hash[str(obj["dn"])] = obj["whenCreated"] @@ -1113,6 +1147,18 @@ def removeProvisionUSN(samdb): delta.dn = entry[0].dn samdb.modify(delta) +def remove_stored_generated_attrs(paths, creds, session, lp): + """Remove previously stored constructed attributes + + :param paths: List of paths for different provision objects + from the upgraded provision + :param creds: A credential object + :param session: A session object + :param lp: A line parser object + :return: An associative array whose key are the different constructed + attributes and the value the dn where this attributes were found. + """ + def simple_update_basesamdb(newpaths, paths, names): """Update the provision container db: sam.ldb @@ -1185,49 +1231,114 @@ def update_samdb(ref_samdb, samdb, names, highestUSN, schema): return 0 -def update_machine_account_password(samdb, secrets_ldb, names): - """Update (change) the password of the current DC both in the SAM db and in - secret one +def copyxattrs(dir, refdir): + """ Copy owner, groups, extended ACL and NT acls from + a reference dir to a destination dir + + Both dir are supposed to hold the same files + :param dir: Destination dir + :param refdir: Reference directory""" + + noxattr = 0 + for root, dirs, files in os.walk(dir, topdown=True): + for name in files: + subdir=root[len(dir):] + ref = os.path.join("%s%s" % (refdir, subdir), name) + statsinfo = os.stat(ref) + tgt = os.path.join(root, name) + try: + + os.chown(tgt, statsinfo.st_uid, statsinfo.st_gid) + # Get the xattr attributes if any + try: + attribute = samba.xattr_native.wrap_getxattr(ref, + xattr.XATTR_NTACL_NAME) + samba.xattr_native.wrap_setxattr(tgt, + xattr.XATTR_NTACL_NAME, + attribute) + except: + noxattr = 1 + attribute = samba.xattr_native.wrap_getxattr(ref, + "system.posix_acl_access") + samba.xattr_native.wrap_setxattr(tgt, + "system.posix_acl_access", + attribute) + except: + continue + for name in dirs: + subdir=root[len(dir):] + ref = os.path.join("%s%s" % (refdir, subdir), name) + statsinfo = os.stat(ref) + tgt = os.path.join(root, name) + try: + os.chown(os.path.join(root, name), statsinfo.st_uid, + statsinfo.st_gid) + try: + attribute = samba.xattr_native.wrap_getxattr(ref, + xattr.XATTR_NTACL_NAME) + samba.xattr_native.wrap_setxattr(tgt, + xattr.XATTR_NTACL_NAME, + attribute) + except: + noxattr = 1 + attribute = samba.xattr_native.wrap_getxattr(ref, + "system.posix_acl_access") + samba.xattr_native.wrap_setxattr(tgt, + "system.posix_acl_access", + attribute) + + except: + continue + + +def backup_provision(paths, dir): + """This function backup the provision files so that a rollback + is possible + + :param paths: Paths to different objects + :param dir: Directory where to store the backup + """ - :param samdb: An LDB object related to the sam.ldb file of a given provision - :param secrets_ldb: An LDB object related to the secrets.ldb file of a given - provision - :param names: List of key provision parameters""" + shutil.copytree(paths.sysvol, os.path.join(dir, "sysvol")) + copyxattrs(os.path.join(dir, "sysvol"), paths.sysvol) + shutil.copy2(paths.samdb, dir) + shutil.copy2(paths.secrets, dir) + shutil.copy2(paths.idmapdb, dir) + shutil.copy2(paths.privilege, dir) + if os.path.isfile(os.path.join(paths.private_dir,"eadb.tdb")): + shutil.copy2(os.path.join(paths.private_dir,"eadb.tdb"), dir) + shutil.copy2(paths.smbconf, dir) + shutil.copy2(os.path.join(paths.private_dir,"secrets.keytab"), dir) - message(SIMPLE, "Update machine account") - expression = "samAccountName=%s$" % names.netbiosname - secrets_msg = secrets_ldb.search(expression=expression, - attrs=["secureChannelType"]) - if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC: - res = samdb.search(expression=expression, attrs=[]) - assert(len(res) == 1) - - msg = Message(res[0].dn) - machinepass = samba.generate_random_password(128, 255) - msg["userPassword"] = MessageElement(machinepass, FLAG_MOD_REPLACE, - "userPassword") - samdb.modify(msg) - - res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname), - attrs=["msDs-keyVersionNumber"]) - assert(len(res) == 1) - kvno = int(str(res[0]["msDs-keyVersionNumber"])) - secChanType = int(secrets_msg[0]["secureChannelType"][0]) - - secretsdb_self_join(secrets_ldb, domain=names.domain, - realm=names.realm or sambaopts._lp.get('realm'), - domainsid=names.domainsid, - dnsdomain=names.dnsdomain, - netbiosname=names.netbiosname, - machinepass=machinepass, - key_version_number=kvno, - secure_channel_type=secChanType) + samldbdir = os.path.join(paths.private_dir, "sam.ldb.d") + if not os.path.isdir(samldbdir): + samldbdir = paths.private_dir + schemaldb = os.path.join(paths.private_dir, "schema.ldb") + configldb = os.path.join(paths.private_dir, "configuration.ldb") + usersldb = os.path.join(paths.private_dir, "users.ldb") + shutil.copy2(schemaldb, dir) + shutil.copy2(usersldb, dir) + shutil.copy2(configldb, dir) else: - raise ProvisioningError("Unable to find a Secure Channel" - "of type SEC_CHAN_BDC") + shutil.copytree(samldbdir, os.path.join(dir, "sam.ldb.d")) + +def sync_calculated_attributes(samdb, names): + """Synchronize attributes used for constructed ones, with the + old constructed that were stored in the database. + + This apply for instance to msds-keyversionnumber that was + stored and that is now constructed from replpropertymetadata. + + :param samdb: An LDB object attached to the currently upgraded samdb + :param names: Various key parameter about current provision. + """ + listAttrs = ["msDs-KeyVersionAttribute"] + hash = search_constructed_attrs_stored(samdb, names.rootdn, listAttrs) + increment_calculated_keyversion_number(samdb, names.rootdn, hash) + def setup_path(file): return os.path.join(setup_dir, file) @@ -1252,12 +1363,13 @@ def setup_path(file): # A) When alpha9 or alphaxx is present # The base sam.ldb file is updated by looking at the difference between # referrence one and the current one. Everything is copied with the -# exception of lastProvisionUSN attributes. The highest used USN -# is fetched so that changed by upgradeprovision usn can be tracked +# exception of lastProvisionUSN attributes. # B) Other case (it reflect that that provision was done before alpha9) # The base sam.ldb of the reference provision is copied over # the current one, if necessary ldb related to partitions are moved # and renamed +# The highest used USN is fetched so that changed by upgradeprovision +# usn can be tracked # 12)A Schema object is created, it will be used to provide a complete # schema to current provision during update (as the schema of the # current provision might not be complete and so won't allow some @@ -1380,157 +1492,172 @@ if __name__ == '__main__': minUSN = 0 # 2) ldbs = get_ldbs(paths, creds, session, lp) - ldbs.startTransactions() - - # 3) Guess all the needed names (variables in fact) from the current - # provision. - names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap, - paths, smbconf, lp) - # 4) - lastProvisionUSNs = get_last_provision_usn(ldbs.sam) - if lastProvisionUSNs is not None: - message(CHANGE, - "Find a last provision USN, %d range(s)" % len(lastProvisionUSNs)) - - # Objects will be created with the admin session - # (not anymore system session) - adm_session = admin_session(lp, str(names.domainsid)) - # So we reget handle on objects - # ldbs = get_ldbs(paths, creds, adm_session, lp) - - if not sanitychecks(ldbs.sam, names): - message(SIMPLE, "Sanity checks for the upgrade fails, checks messages" - " and correct them before rerunning upgradeprovision") - sys.exit(1) - - # Let's see provision parameters - print_provision_key_parameters(names) - - # 5) With all this information let's create a fresh new provision used as - # reference - message(SIMPLE, "Creating a reference provision") - provisiondir = tempfile.mkdtemp(dir=paths.private_dir, - prefix="referenceprovision") - newprovision(names, setup_dir, creds, session, smbconf, provisiondir, - provision_logger) - - # TODO - # 6) and 7) - # We need to get a list of object which SD is directly computed from - # defaultSecurityDescriptor. - # This will allow us to know which object we can rebuild the SD in case - # of change of the parent's SD or of the defaultSD. - # Get file paths of this new provision - newpaths = get_paths(param, targetdir=provisiondir) - new_ldbs = get_ldbs(newpaths, creds, session, lp) - new_ldbs.startTransactions() - - # 8) Populate some associative array to ease the update process - # List of attribute which are link and backlink - populate_links(new_ldbs.sam, names.schemadn) - # List of attribute with ASN DN synthax) - populate_dnsyntax(new_ldbs.sam, names.schemadn) - # 9) - update_privilege(newpaths.private_dir, paths.private_dir) - # 10) - oem = getOEMInfo(ldbs.sam, str(names.rootdn)) - # Do some modification on sam.ldb - ldbs.groupedCommit() - # 11) - if re.match(".*alpha((9)|(\d\d+)).*", str(oem)): - # 11) A - # Starting from alpha9 we can consider that the structure is quite ok - # and that we should do only dela + backupdir = tempfile.mkdtemp(dir=paths.private_dir, + prefix="backupprovision") + backup_provision(paths, backupdir) + try: + ldbs.startTransactions() + + # 3) Guess all the needed names (variables in fact) from the current + # provision. + names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap, + paths, smbconf, lp) + # 4) + lastProvisionUSNs = get_last_provision_usn(ldbs.sam) + if lastProvisionUSNs is not None: + message(CHANGE, + "Find a last provision USN, %d range(s)" % len(lastProvisionUSNs)) + + # Objects will be created with the admin session + # (not anymore system session) + adm_session = admin_session(lp, str(names.domainsid)) + # So we reget handle on objects + # ldbs = get_ldbs(paths, creds, adm_session, lp) + + if not sanitychecks(ldbs.sam, names): + message(SIMPLE, "Sanity checks for the upgrade fails, checks messages" + " and correct them before rerunning upgradeprovision") + sys.exit(1) + + # Let's see provision parameters + print_provision_key_parameters(names) + + # 5) With all this information let's create a fresh new provision used as + # reference + message(SIMPLE, "Creating a reference provision") + provisiondir = tempfile.mkdtemp(dir=paths.private_dir, + prefix="referenceprovision") + newprovision(names, setup_dir, creds, session, smbconf, provisiondir, + provision_logger) + + # TODO + # 6) and 7) + # We need to get a list of object which SD is directly computed from + # defaultSecurityDescriptor. + # This will allow us to know which object we can rebuild the SD in case + # of change of the parent's SD or of the defaultSD. + # Get file paths of this new provision + newpaths = get_paths(param, targetdir=provisiondir) + new_ldbs = get_ldbs(newpaths, creds, session, lp) + new_ldbs.startTransactions() + + # 8) Populate some associative array to ease the update process + # List of attribute which are link and backlink + populate_links(new_ldbs.sam, names.schemadn) + # List of attribute with ASN DN synthax) + populate_dnsyntax(new_ldbs.sam, names.schemadn) + # 9) + update_privilege(newpaths.private_dir, paths.private_dir) + # 10) + oem = getOEMInfo(ldbs.sam, str(names.rootdn)) + # Do some modification on sam.ldb + ldbs.groupedCommit() new_ldbs.groupedCommit() - delta_update_basesamdb(newpaths.samdb, paths.samdb, creds, session, lp, message) + + # 11) + if re.match(".*alpha((9)|(\d\d+)).*", str(oem)): + # 11) A + # Starting from alpha9 we can consider that the structure is quite ok + # and that we should do only dela + delta_update_basesamdb(newpaths.samdb, paths.samdb, creds, session, lp, message) + else: + # 11) B + simple_update_basesamdb(newpaths, paths, names) + ldbs = get_ldbs(paths, creds, session, lp) + removeProvisionUSN(ldbs.sam) + ldbs.startTransactions() minUSN = int(str(get_max_usn(ldbs.sam, str(names.rootdn)))) + 1 new_ldbs.startTransactions() - else: - # 11) B - simple_update_basesamdb(newpaths, paths, names) - ldbs = get_ldbs(paths, creds, session, lp) - removeProvisionUSN(ldbs.sam) - ldbs.startTransactions() - # 12) - schema = Schema(setup_path, names.domainsid, schemadn=str(names.schemadn), - serverdn=str(names.serverdn)) - # 13) - if opts.full: - if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs, - schema): - message(SIMPLE, "Rollbacking every changes. Check the reason" - " of the problem") - message(SIMPLE, "In any case your system as it was before" - " the upgrade") - ldbs.groupedRollback() - new_ldbs.groupedRollback() - shutil.rmtree(provisiondir) - sys.exit(1) - # 14) - update_secrets(new_ldbs.secrets, ldbs.secrets, message) - # 15) - update_machine_account_password(ldbs.sam, ldbs.secrets, names) - - # 16) SD should be created with admin but as some previous acl were so wrong - # that admin can't modify them we have first to recreate them with the good - # form but with system account and then give the ownership to admin ... - if not re.match(r'.*alpha(9|\d\d+)', str(oem)): - message(SIMPLE, "Fixing old povision SD") - fix_partition_sd(ldbs.sam, names) - rebuild_sd(ldbs.sam, names) - - # We calculate the max USN before recalculating the SD because we might - # touch object that have been modified after a provision and we do not - # want that the next upgradeprovision thinks that it has a green light - # to modify them - - # 17) - maxUSN = get_max_usn(ldbs.sam, str(names.rootdn)) - - # 18) We rebuild SD only if defaultSecurityDescriptor is modified - # But in fact we should do it also if one object has its SD modified as - # child might need rebuild - if defSDmodified: - message(SIMPLE, "Updating SD") - ldbs.sam.set_session_info(adm_session) - # Alpha10 was a bit broken still - if re.match(r'.*alpha(\d|10)', str(oem)): + # 12) + schema = Schema(setup_path, names.domainsid, schemadn=str(names.schemadn), + serverdn=str(names.serverdn)) + + # 13) + if opts.full: + if not update_samdb(new_ldbs.sam, ldbs.sam, names, lastProvisionUSNs, + schema): + message(SIMPLE, "Rollbacking every changes. Check the reason" + " of the problem") + message(SIMPLE, "In any case your system as it was before" + " the upgrade") + ldbs.groupedRollback() + new_ldbs.groupedRollback() + shutil.rmtree(provisiondir) + sys.exit(1) + else: + sync_calculated_attributes(ldbs.sam, names) + # 14) + update_secrets(new_ldbs.secrets, ldbs.secrets, message) + # 15) + message(SIMPLE, "Update machine account") + update_machine_account_password(ldbs.sam, ldbs.secrets, names) + + # 16) SD should be created with admin but as some previous acl were so wrong + # that admin can't modify them we have first to recreate them with the good + # form but with system account and then give the ownership to admin ... + if not re.match(r'.*alpha(9|\d\d+)', str(oem)): + message(SIMPLE, "Fixing old povision SD") fix_partition_sd(ldbs.sam, names) - rebuild_sd(ldbs.sam, names) - - # 19) - # Now we are quite confident in the recalculate process of the SD, we make - # it optional. - # Also the check must be done in a clever way as for the moment we just - # compare SDDL - if opts.debugchangesd: - check_updated_sd(new_ldbs.sam, ldbs.sam, names) - - # 20) - updateOEMInfo(ldbs.sam, str(names.rootdn)) - # 21) - check_for_DNS(newpaths.private_dir, paths.private_dir) - # 22) - if lastProvisionUSNs is not None: - update_provision_usn(ldbs.sam, minUSN, maxUSN) - if opts.full and (names.policyid is None or names.policyid_dc is None): - update_policyids(names, ldbs.sam) - if opts.full or opts.resetfileacl: - try: - update_gpo(paths, ldbs.sam, names, lp, message, 1) - except ProvisioningError, e: - message(ERROR, "The policy for domain controller is missing," - " you should restart upgradeprovision with --full") - else: - try: - update_gpo(paths, ldbs.sam, names, lp, message, 0) - except ProvisioningError, e: - message(ERROR, "The policy for domain controller is missing," - " you should restart upgradeprovision with --full") - ldbs.groupedCommit() - new_ldbs.groupedCommit() - message(SIMPLE, "Upgrade finished !") - # remove reference provision now that everything is done ! - shutil.rmtree(provisiondir) + rebuild_sd(ldbs.sam, names) + + # We calculate the max USN before recalculating the SD because we might + # touch object that have been modified after a provision and we do not + # want that the next upgradeprovision thinks that it has a green light + # to modify them + + # 17) + maxUSN = get_max_usn(ldbs.sam, str(names.rootdn)) + + # 18) We rebuild SD only if defaultSecurityDescriptor is modified + # But in fact we should do it also if one object has its SD modified as + # child might need rebuild + if defSDmodified: + message(SIMPLE, "Updating SD") + ldbs.sam.set_session_info(adm_session) + # Alpha10 was a bit broken still + if re.match(r'.*alpha(\d|10)', str(oem)): + fix_partition_sd(ldbs.sam, names) + rebuild_sd(ldbs.sam, names) + + # 19) + # Now we are quite confident in the recalculate process of the SD, we make + # it optional. + # Also the check must be done in a clever way as for the moment we just + # compare SDDL + if opts.debugchangesd: + check_updated_sd(new_ldbs.sam, ldbs.sam, names) + + # 20) + updateOEMInfo(ldbs.sam, str(names.rootdn)) + # 21) + check_for_DNS(newpaths.private_dir, paths.private_dir) + # 22) + if lastProvisionUSNs is not None: + update_provision_usn(ldbs.sam, minUSN, maxUSN) + if opts.full and (names.policyid is None or names.policyid_dc is None): + update_policyids(names, ldbs.sam) + if opts.full or opts.resetfileacl: + try: + update_gpo(paths, ldbs.sam, names, lp, message, 1) + except ProvisioningError, e: + message(ERROR, "The policy for domain controller is missing," + " you should restart upgradeprovision with --full") + else: + try: + update_gpo(paths, ldbs.sam, names, lp, message, 0) + except ProvisioningError, e: + message(ERROR, "The policy for domain controller is missing," + " you should restart upgradeprovision with --full") + ldbs.groupedCommit() + new_ldbs.groupedCommit() + message(SIMPLE, "Upgrade finished !") + # remove reference provision now that everything is done ! + shutil.rmtree(provisiondir) + except StandardError, err: + message(ERROR,"A problem has occured when trying to upgrade your provision," + " a full backup is located at %s" % backupdir) + if opts.changeall: + (typ, val, tb) = sys.exc_info() + traceback.print_exception(typ, val, tb) diff --git a/source4/scripting/devel/chgtdcpass b/source4/scripting/devel/chgtdcpass new file mode 100755 index 0000000000..1030531363 --- /dev/null +++ b/source4/scripting/devel/chgtdcpass @@ -0,0 +1,63 @@ +#!/usr/bin/env python +# +# Copyright (C) Matthieu Patou <mat@matws.net> 2010 +# +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +import optparse +import sys +# Allow to run from s4 source directory (without installing samba) +sys.path.insert(0, "bin/python") + +import samba.getopt as options +from samba.credentials import DONT_USE_KERBEROS +from samba.auth import system_session +from samba import param +from samba.upgradehelpers import (get_paths, + find_provision_key_parameters, get_ldbs, + update_machine_account_password) + +__docformat__ = "restructuredText" + + +parser = optparse.OptionParser("provision [options]") +sambaopts = options.SambaOptions(parser) +parser.add_option_group(sambaopts) +parser.add_option_group(options.VersionOptions(parser)) +credopts = options.CredentialsOptions(parser) +parser.add_option_group(credopts) + +opts = parser.parse_args()[0] + + +lp = sambaopts.get_loadparm() +smbconf = lp.configfile +creds = credopts.get_credentials(lp) +creds.set_kerberos_state(DONT_USE_KERBEROS) + + +if __name__ == '__main__': + paths = get_paths(param, smbconf=smbconf) + session = system_session() + + ldbs = get_ldbs(paths, creds, session, lp) + ldbs.startTransactions() + + names = find_provision_key_parameters(ldbs.sam, ldbs.secrets, ldbs.idmap, + paths, smbconf, lp) + + update_machine_account_password(ldbs.sam, ldbs.secrets, names) + ldbs.groupedCommit() diff --git a/source4/scripting/python/samba/provision.py b/source4/scripting/python/samba/provision.py index 5ede869015..8be3f655d2 100644 --- a/source4/scripting/python/samba/provision.py +++ b/source4/scripting/python/samba/provision.py @@ -680,17 +680,16 @@ def secretsdb_self_join(secretsdb, domain, "krb5Keytab", "privateKeytab"] - + #We don't need to set msg["flatname"] here, because rdn_name will handle it, and it causes problems for modifies anyway msg = ldb.Message(ldb.Dn(secretsdb, "flatname=%s,cn=Primary Domains" % domain)) - msg["secureChannelType"] = str(secure_channel_type) - msg["flatname"] = [domain] + msg["secureChannelType"] = [str(secure_channel_type)] msg["objectClass"] = ["top", "primaryDomain"] if realm is not None: if dnsdomain is None: dnsdomain = realm.lower() msg["objectClass"] = ["top", "primaryDomain", "kerberosSecret"] - msg["realm"] = realm - msg["saltPrincipal"] = "host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper()) + msg["realm"] = [realm] + msg["saltPrincipal"] = ["host/%s.%s@%s" % (netbiosname.lower(), dnsdomain.lower(), realm.upper())] msg["msDS-KeyVersionNumber"] = [str(key_version_number)] msg["privateKeytab"] = ["secrets.keytab"] @@ -701,30 +700,39 @@ def secretsdb_self_join(secretsdb, domain, if domainsid is not None: msg["objectSid"] = [ndr_pack(domainsid)] + # This complex expression tries to ensure that we don't have more + # than one record for this SID, realm or netbios domain at a time, + # but we don't delete the old record that we are about to modify, + # because that would delete the keytab and previous password. res = secretsdb.search(base="cn=Primary Domains", attrs=attrs, - expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain))" % (domain, realm, str(domainsid))), + expression=("(&(|(flatname=%s)(realm=%s)(objectSid=%s))(objectclass=primaryDomain)(!(dn=%s)))" % (domain, realm, str(domainsid), str(msg.dn))), scope=ldb.SCOPE_ONELEVEL) for del_msg in res: - if del_msg.dn is not msg.dn: secretsdb.delete(del_msg.dn) res = secretsdb.search(base=msg.dn, attrs=attrs, scope=ldb.SCOPE_BASE) if len(res) == 1: - msg["priorSecret"] = res[0]["secret"] - msg["priorWhenChanged"] = res[0]["whenChanged"] + msg["priorSecret"] = [res[0]["secret"][0]] + msg["priorWhenChanged"] = [res[0]["whenChanged"][0]] - if res["privateKeytab"] is not None: - msg["privateKeytab"] = res[0]["privateKeytab"] + try: + msg["privateKeytab"] = [res[0]["privateKeytab"][0]] + except KeyError: + pass - if res["krb5Keytab"] is not None: - msg["krb5Keytab"] = res[0]["krb5Keytab"] + try: + msg["krb5Keytab"] = [res[0]["krb5Keytab"][0]] + except KeyError: + pass for el in msg: - el.set_flags(ldb.FLAG_MOD_REPLACE) - secretsdb.modify(msg) + if el != 'dn': + msg[el].set_flags(ldb.FLAG_MOD_REPLACE) + secretsdb.modify(msg) + secretsdb.rename(res[0].dn, msg.dn) else: secretsdb.add(msg) diff --git a/source4/scripting/python/samba/samdb.py b/source4/scripting/python/samba/samdb.py index f810926710..f358747b51 100644 --- a/source4/scripting/python/samba/samdb.py +++ b/source4/scripting/python/samba/samdb.py @@ -28,12 +28,16 @@ import samba import ldb import time import base64 +from samba.ndr import ndr_unpack, ndr_pack +from samba.dcerpc import drsblobs, misc __docformat__ = "restructuredText" class SamDB(samba.Ldb): """The SAM database.""" + hash_oid_name = {} + def __init__(self, url=None, lp=None, modules_dir=None, session_info=None, credentials=None, flags=0, options=None, global_schema=True, auto_connect=True, am_rodc=False): @@ -470,5 +474,104 @@ accountExpires: %u def set_schema_from_ldb(self, ldb): dsdb._dsdb_set_schema_from_ldb(self, ldb) + def get_attribute_from_attid(self, attid): + """ Get from an attid the associated attribute + + :param attid: The attribute id for searched attribute + :return: The name of the attribute associated with this id + """ + if len(self.hash_oid_name.keys()) == 0: + self._populate_oid_attid() + if self.hash_oid_name.has_key(self.get_oid_from_attid(attid)): + return self.hash_oid_name[self.get_oid_from_attid(attid)] + else: + return None + + + def _populate_oid_attid(self): + """Populate the hash hash_oid_name + + This hash contains the oid of the attribute as a key and + its display name as a value + """ + self.hash_oid_name = {} + res = self.search(expression="objectClass=attributeSchema", + controls=["search_options:1:2"], + attrs=["attributeID", + "lDAPDisplayName"]) + if len(res) > 0: + for e in res: + strDisplay = str(e.get("lDAPDisplayName")) + self.hash_oid_name[str(e.get("attributeID"))] = strDisplay + + + def get_attribute_replmetadata_version(self, dn, att): + """ Get the version field trom the replPropertyMetaData for + the given field + + :param dn: The on which we want to get the version + :param att: The name of the attribute + :return: The value of the version field in the replPropertyMetaData + for the given attribute. None if the attribute is not replicated + """ + + res = self.search(expression="dn=%s" % dn, + scope=ldb.SCOPE_SUBTREE, + controls=["search_options:1:2"], + attrs=["replPropertyMetaData"]) + if len(res) == 0: + return None + + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + if len(self.hash_oid_name.keys()) == 0: + self._populate_oid_attid() + for o in ctr.array: + # Search for Description + att_oid = self.get_oid_from_attid(o.attid) + if self.hash_oid_name.has_key(att_oid) and\ + att.lower() == self.hash_oid_name[att_oid].lower(): + return o.version + return None + + + def set_attribute_replmetadata_version(self, dn, att, value): + res = self.search(expression="dn=%s" % dn, + scope=ldb.SCOPE_SUBTREE, + controls=["search_options:1:2"], + attrs=["replPropertyMetaData"]) + if len(res) == 0: + return None + + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + now = samba.unix2nttime(int(time.time())) + found = False + if len(self.hash_oid_name.keys()) == 0: + self._populate_oid_attid() + for o in ctr.array: + # Search for Description + att_oid = self.get_oid_from_attid(o.attid) + if self.hash_oid_name.has_key(att_oid) and\ + att.lower() == self.hash_oid_name[att_oid].lower(): + found = True + seq = self.sequence_number(ldb.SEQ_NEXT) + o.version = value + o.originating_change_time = now + o.originating_invocation_id = misc.GUID(self.get_invocation_id()) + o.originating_usn = seq + o.local_usn = seq + if found : + replBlob = ndr_pack(repl) + msg = ldb.Message() + msg.dn = res[0].dn + msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, + ldb.FLAG_MOD_REPLACE, + "replPropertyMetaData") + self.modify(msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) + + def write_prefixes_from_schema(self): dsdb._dsdb_write_prefixes_from_schema_to_ldb(self) diff --git a/source4/scripting/python/samba/tests/dsdb.py b/source4/scripting/python/samba/tests/dsdb.py index c19dbaab47..4a50c96e25 100644 --- a/source4/scripting/python/samba/tests/dsdb.py +++ b/source4/scripting/python/samba/tests/dsdb.py @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Unix SMB/CIFS implementation. Tests for dsdb +# Unix SMB/CIFS implementation. Tests for dsdb # Copyright (C) Matthieu Patou <mat@matws.net> 2010 # # This program is free software; you can redistribute it and/or modify @@ -17,26 +17,117 @@ # along with this program. If not, see <http://www.gnu.org/licenses/>. # -import samba.dsdb from samba.credentials import Credentials from samba.samdb import SamDB from samba.auth import system_session from testtools.testcase import TestCase +from samba.ndr import ndr_unpack, ndr_pack +from samba.dcerpc import drsblobs +import ldb import os +import samba class DsdbTests(TestCase): - def _baseprovpath(self): + + def setUp(self): + super(DsdbTests, self).setUp() + self.lp = samba.param.LoadParm() + self.lp.load(os.path.join(os.path.join(self.baseprovpath(), "etc"), "smb.conf")) + self.creds = Credentials() + self.creds.guess(self.lp) + self.session = system_session() + self.samdb = SamDB(os.path.join(self.baseprovpath(), "private", "sam.ldb"), + session_info=self.session, credentials=self.creds,lp=self.lp) + + + def baseprovpath(self): return os.path.join(os.environ['SELFTEST_PREFIX'], "dc") + def test_get_oid_from_attrid(self): - lp = samba.param.LoadParm() - lp.load(os.path.join(os.path.join(self._baseprovpath(), "etc"), "smb.conf")) - creds = Credentials() - creds.guess(lp) - session = system_session() - test_ldb = SamDB(os.path.join(self._baseprovpath(), "private", "sam.ldb"), - session_info=session, credentials=creds,lp=lp) - oid = test_ldb.get_oid_from_attid(591614) + oid = self.samdb.get_oid_from_attid(591614) self.assertEquals(oid, "1.2.840.113556.1.4.1790") + + def test_error_replpropertymetadata(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["replPropertyMetaData"]) + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + for o in ctr.array: + # Search for Description + if o.attid == 13: + old_version = o.version + o.version = o.version + 1 + replBlob = ndr_pack(repl) + msg = ldb.Message() + msg.dn = res[0].dn + msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") + self.assertRaises(ldb.LdbError, self.samdb.modify, msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) + + def test_twoatt_replpropertymetadata(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["replPropertyMetaData", "uSNChanged"]) + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + for o in ctr.array: + # Search for Description + if o.attid == 13: + old_version = o.version + o.version = o.version + 1 + o.local_usn = long(str(res[0]["uSNChanged"])) + 1 + replBlob = ndr_pack(repl) + msg = ldb.Message() + msg.dn = res[0].dn + msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") + msg["description"] = ldb.MessageElement("new val", ldb.FLAG_MOD_REPLACE, "description") + self.assertRaises(ldb.LdbError, self.samdb.modify, msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) + + def test_set_replpropertymetadata(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["replPropertyMetaData", "uSNChanged"]) + repl = ndr_unpack(drsblobs.replPropertyMetaDataBlob, + str(res[0]["replPropertyMetaData"])) + ctr = repl.ctr + for o in ctr.array: + # Search for Description + if o.attid == 13: + old_version = o.version + o.version = o.version + 1 + o.local_usn = long(str(res[0]["uSNChanged"])) + 1 + o.originating_usn = long(str(res[0]["uSNChanged"])) + 1 + replBlob = ndr_pack(repl) + msg = ldb.Message() + msg.dn = res[0].dn + msg["replPropertyMetaData"] = ldb.MessageElement(replBlob, ldb.FLAG_MOD_REPLACE, "replPropertyMetaData") + self.samdb.modify(msg, ["local_oid:1.3.6.1.4.1.7165.4.3.14:0"]) + + def test_ok_get_attribute_from_attid(self): + self.assertEquals(self.samdb.get_attribute_from_attid(13), "description") + + def test_ko_get_attribute_from_attid(self): + self.assertEquals(self.samdb.get_attribute_from_attid(11979), None) + + def test_get_attribute_replmetadata_version(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["dn"]) + self.assertEquals(len(res), 1) + dn = str(res[0].dn) + self.assertEqual(self.samdb.get_attribute_replmetadata_version(dn, "unicodePwd"), 1) + + def test_set_attribute_replmetadata_version(self): + res = self.samdb.search(expression="cn=Administrator", + scope=ldb.SCOPE_SUBTREE, + attrs=["dn"]) + self.assertEquals(len(res), 1) + dn = str(res[0].dn) + version = self.samdb.get_attribute_replmetadata_version(dn, "description") + self.samdb.set_attribute_replmetadata_version(dn, "description", version + 2) + self.assertEqual(self.samdb.get_attribute_replmetadata_version(dn, "description"), version + 2) diff --git a/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py b/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py index b32ffc6155..e30906fc6b 100644 --- a/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py +++ b/source4/scripting/python/samba/tests/upgradeprovisionneeddc.py @@ -29,7 +29,8 @@ from samba.upgradehelpers import (get_paths, get_ldbs, find_provision_key_parameters, identic_rename, updateOEMInfo, getOEMInfo, update_gpo, delta_update_basesamdb, - search_constructed_attrs_stored) + search_constructed_attrs_stored, + increment_calculated_keyversion_number) from samba.tests import env_loadparm, TestCaseInTempDir from samba.tests.provision import create_dummy_secretsdb import ldb @@ -91,6 +92,29 @@ class UpgradeProvisionWithLdbTestCase(TestCaseInTempDir): ["msds-KeyVersionNumber"]) self.assertFalse(hashAtt.has_key("msds-KeyVersionNumber")) + def test_increment_calculated_keyversion_number(self): + dn = "CN=Administrator,CN=Users,%s" % self.names.rootdn + # We conctruct a simple hash for the user administrator + hash = {} + # And we want the version to be 140 + hash[dn.lower()] = 140 + + increment_calculated_keyversion_number(self.ldbs.sam, + self.names.rootdn, + hash) + self.assertEqual(self.ldbs.sam.get_attribute_replmetadata_version(dn, + "unicodePwd"), + 140) + # This function should not decrement the version + hash[dn.lower()] = 130 + + increment_calculated_keyversion_number(self.ldbs.sam, + self.names.rootdn, + hash) + self.assertEqual(self.ldbs.sam.get_attribute_replmetadata_version(dn, + "unicodePwd"), + 140) + def test_identic_rename(self): rootdn = "DC=samba,DC=example,DC=com" diff --git a/source4/scripting/python/samba/upgradehelpers.py b/source4/scripting/python/samba/upgradehelpers.py index 74a157d041..58106e0a70 100755 --- a/source4/scripting/python/samba/upgradehelpers.py +++ b/source4/scripting/python/samba/upgradehelpers.py @@ -35,8 +35,9 @@ import ldb from samba.provision import (ProvisionNames, provision_paths_from_lp, getpolicypath, set_gpo_acl, create_gpo_struct, FILL_FULL, provision, ProvisioningError, - setsysvolacl) + setsysvolacl, secretsdb_self_join) from samba.dcerpc import misc, security, xattr +from samba.dcerpc.misc import SEC_CHAN_BDC from samba.ndr import ndr_unpack from samba.samdb import SamDB @@ -703,14 +704,48 @@ def update_gpo(paths, samdb, names, lp, message, force=0): set_gpo_acl(paths.sysvol, names.dnsdomain, names.domainsid, names.domaindn, samdb, lp) except TypeError, e: - message(ERROR, "Unable to set ACLs on policies related objects, if not using posix:eadb, you must be root to do it") + message(ERROR, "Unable to set ACLs on policies related objects," + " if not using posix:eadb, you must be root to do it") if resetacls: try: setsysvolacl(samdb, paths.netlogon, paths.sysvol, names.wheel_gid, names.domainsid, names.dnsdomain, names.domaindn, lp) except TypeError, e: - message(ERROR, "Unable to set ACLs on sysvol share, if not using posix:eadb, you must be root to do it") + message(ERROR, "Unable to set ACLs on sysvol share, if not using" + "posix:eadb, you must be root to do it") + +def increment_calculated_keyversion_number(samdb, rootdn, hashDns): + """For a given hash associating dn and a number, this function will + update the replPropertyMetaData of each dn in the hash, so that the + calculated value of the msDs-KeyVersionNumber is equal or superior to the + one associated to the given dn. + + :param samdb: An SamDB object pointing to the sam + :param rootdn: The base DN where we want to start + :param hashDns: A hash with dn as key and number representing the + minimum value of msDs-KeyVersionNumber that we want to + have + """ + entry = samdb.search(expression='(objectClass=user)', + base=ldb.Dn(samdb,str(rootdn)), + scope=SCOPE_SUBTREE, attrs=["msDs-KeyVersionNumber"], + controls=["search_options:1:2"]) + done = 0 + if len(entry) == 0: + raise ProvisioningError("Unable to find msDs-KeyVersionNumber") + else: + for e in entry: + if hashDns.has_key(str(e.dn).lower()): + done = done + 1 + val = e.get("msDs-KeyVersionNumber") + if not val: + continue + version = int(str(hashDns[str(e.dn).lower()])) + if int(str(val)) < version: + samdb.set_attribute_replmetadata_version(str(e.dn), + "unicodePwd", + version) def delta_update_basesamdb(refsam, sam, creds, session, lp, message): """Update the provision container db: sam.ldb @@ -770,6 +805,48 @@ def construct_existor_expr(attrs): expr = "%s)"%expr return expr +def update_machine_account_password(samdb, secrets_ldb, names): + """Update (change) the password of the current DC both in the SAM db and in + secret one + + :param samdb: An LDB object related to the sam.ldb file of a given provision + :param secrets_ldb: An LDB object related to the secrets.ldb file of a given + provision + :param names: List of key provision parameters""" + + expression = "samAccountName=%s$" % names.netbiosname + secrets_msg = secrets_ldb.search(expression=expression, + attrs=["secureChannelType"]) + if int(secrets_msg[0]["secureChannelType"][0]) == SEC_CHAN_BDC: + res = samdb.search(expression=expression, attrs=[]) + assert(len(res) == 1) + + msg = ldb.Message(res[0].dn) + machinepass = samba.generate_random_password(128, 255) + msg["userPassword"] = ldb.MessageElement(machinepass, + ldb.FLAG_MOD_REPLACE, + "userPassword") + samdb.modify(msg) + + res = samdb.search(expression=("samAccountName=%s$" % names.netbiosname), + attrs=["msDs-keyVersionNumber"]) + assert(len(res) == 1) + kvno = int(str(res[0]["msDs-keyVersionNumber"])) + secChanType = int(secrets_msg[0]["secureChannelType"][0]) + + secretsdb_self_join(secrets_ldb, domain=names.domain, + realm=names.realm, + domainsid=names.domainsid, + dnsdomain=names.dnsdomain, + netbiosname=names.netbiosname, + machinepass=machinepass, + key_version_number=kvno, + secure_channel_type=secChanType) + else: + raise ProvisioningError("Unable to find a Secure Channel" + "of type SEC_CHAN_BDC") + + def search_constructed_attrs_stored(samdb, rootdn, attrs): """Search a given sam DB for calculated attributes that are still stored in the db. @@ -786,7 +863,7 @@ def search_constructed_attrs_stored(samdb, rootdn, attrs): expr = construct_existor_expr(attrs) if expr == "": return hashAtt - entry = samdb.search(expression=expr, base=ldb.Dn(samdb,str(rootdn)), + entry = samdb.search(expression=expr, base=ldb.Dn(samdb, str(rootdn)), scope=SCOPE_SUBTREE, attrs=attrs, controls=["search_options:1:2","bypassoperational:0"]) if len(entry) == 0: diff --git a/source4/selftest/tests.sh b/source4/selftest/tests.sh index c70eb877cf..52d1d3963e 100755 --- a/source4/selftest/tests.sh +++ b/source4/selftest/tests.sh @@ -363,11 +363,11 @@ planperltestsuite "selftest.samba4.pl" none $samba4srcdir/../selftest/test_samba # work correctly. plantestsuite "blackbox.ndrdump" none $samba4srcdir/librpc/tests/test_ndrdump.sh -plantestsuite "blackbox.net" dc $samba4srcdir/utils/tests/test_net.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$DOMAIN" -plantestsuite "blackbox.pkinit" dc $bbdir/test_pkinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION -plantestsuite "blackbox.kinit" dc $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION -plantestsuite "blackbox.kinit" fl2000dc $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" arcfour-hmac-md5 $CONFIGURATION -plantestsuite "blackbox.kinit" fl2008r2dc $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION +plantestsuite "blackbox.net" dc:local $samba4srcdir/utils/tests/test_net.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$DOMAIN" +plantestsuite "blackbox.pkinit" dc:local $bbdir/test_pkinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION +plantestsuite "blackbox.kinit" dc:local $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION +plantestsuite "blackbox.kinit" fl2000dc:local $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" arcfour-hmac-md5 $CONFIGURATION +plantestsuite "blackbox.kinit" fl2008r2dc:local $bbdir/test_kinit.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $CONFIGURATION plantestsuite "blackbox.passwords" dc:local $bbdir/test_passwords.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$REALM" "\$DOMAIN" "$PREFIX" plantestsuite "blackbox.export.keytab" dc:local $bbdir/test_export_keytab.sh "\$SERVER" "\$USERNAME" "\$REALM" "\$DOMAIN" "$PREFIX" plantestsuite "blackbox.cifsdd" dc $samba4srcdir/client/tests/test_cifsdd.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$DOMAIN" @@ -378,6 +378,7 @@ plantestsuite "blackbox.masktest" dc $samba4srcdir/torture/tests/test_masktest.s plantestsuite "blackbox.gentest" dc $samba4srcdir/torture/tests/test_gentest.sh "\$SERVER" "\$USERNAME" "\$PASSWORD" "\$DOMAIN" "$PREFIX" plantestsuite "blackbox.wbinfo" dc:local $samba4srcdir/../nsswitch/tests/test_wbinfo.sh "\$DOMAIN" "\$USERNAME" "\$PASSWORD" "dc" plantestsuite "blackbox.wbinfo" member:local $samba4srcdir/../nsswitch/tests/test_wbinfo.sh "\$DOMAIN" "\$DC_USERNAME" "\$DC_PASSWORD" "member" +plantestsuite "blackbox.chgdcpass" dc $bbdir/test_chgdcpass.sh "\$SERVER" "LOCALDC\\\$" "\$REALM" "\$DOMAIN" "$PREFIX" aes256-cts-hmac-sha1-96 $SELFTEST_PREFIX/dc # Tests using the "Simple" NTVFS backend diff --git a/source4/setup/schema_samba4.ldif b/source4/setup/schema_samba4.ldif index 681aa96898..aecd273a18 100644 --- a/source4/setup/schema_samba4.ldif +++ b/source4/setup/schema_samba4.ldif @@ -186,6 +186,7 @@ #Allocated: DSDB_CONTROL_APPLY_LINKS 1.3.6.1.4.1.7165.4.3.11 #Allocated: DSDB_CONTROL_BYPASS_PASSWORD_HASH_OID 1.3.6.1.4.1.7165.4.3.12 #Allocated: LDB_CONTROL_BYPASSOPERATIONAL_OID 1.3.6.1.4.1.7165.4.3.13 +#Allocated: DSDB_CONTROL_CHANGEREPLMETADATA_OID 1.3.6.1.4.1.7165.4.3.14 # Extended 1.3.6.1.4.1.7165.4.4.x #Allocated: DSDB_EXTENDED_REPLICATED_OBJECTS_OID 1.3.6.1.4.1.7165.4.4.1 diff --git a/source4/utils/tests/test_net.sh b/source4/utils/tests/test_net.sh index e49989ff81..09394f41be 100755 --- a/source4/utils/tests/test_net.sh +++ b/source4/utils/tests/test_net.sh @@ -29,8 +29,6 @@ testit() { return $status } -testit "domain join" $VALGRIND $net join $DOMAIN $CONFIGURATION -W "$DOMAIN" -U"$USERNAME%$PASSWORD" $@ - testit "Test login with --machine-pass without kerberos" $VALGRIND $smbclient -c 'ls' $CONFIGURATION //$SERVER/tmp --machine-pass -k no testit "Test login with --machine-pass and kerberos" $VALGRIND $smbclient -c 'ls' $CONFIGURATION //$SERVER/tmp --machine-pass -k yes |