/** * Canonicalize a message, merging elements of the same name */ int ldb_msg_normalize(struct ldb_context *ldb, TALLOC_CTX *mem_ctx, const struct ldb_message *msg, struct ldb_message **_msg_out) { unsigned int i; struct ldb_message *msg2; msg2 = ldb_msg_copy(mem_ctx, msg); if (msg2 == NULL) { return LDB_ERR_OPERATIONS_ERROR; } ldb_msg_sort_elements(msg2); for (i=1; i < msg2->num_elements; i++) { struct ldb_message_element *el1 = &msg2->elements[i-1]; struct ldb_message_element *el2 = &msg2->elements[i]; if (ldb_msg_element_compare_name(el1, el2) == 0) { el1->values = talloc_realloc(msg2->elements, el1->values, struct ldb_val, el1->num_values + el2->num_values); if (el1->num_values + el2->num_values > 0 && el1->values == NULL) { talloc_free(msg2); return LDB_ERR_OPERATIONS_ERROR; } memcpy(el1->values + el1->num_values, el2->values, sizeof(struct ldb_val) * el2->num_values); el1->num_values += el2->num_values; talloc_free(discard_const_p(char, el2->name)); if ((i+1) < msg2->num_elements) { memmove(el2, el2+1, sizeof(struct ldb_message_element) * (msg2->num_elements - (i+1))); } msg2->num_elements--; i--; } }
static int samldb_fill_foreignSecurityPrincipal_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg) { struct ldb_message *msg2; const char *rdn_name; struct dom_sid *dom_sid; struct dom_sid *sid; const char *dom_attrs[] = { "name", NULL }; struct ldb_message **dom_msgs; const char *errstr; int ret; TALLOC_CTX *mem_ctx = talloc_new(msg); if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* build the new msg */ msg2 = ldb_msg_copy(mem_ctx, msg); if (!msg2) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_foreignSecurityPrincpal_object: ldb_msg_copy failed!\n"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateForeignSecurityPrincipal)(objectclass=foreignSecurityPrincipalTemplate))", &errstr); if (ret != 0) { ldb_asprintf_errstring(module->ldb, "samldb_fill_foreignSecurityPrincipal_object: " "Error copying template: %s", errstr); talloc_free(mem_ctx); return ret; } rdn_name = ldb_dn_get_rdn_name(msg2->dn); if (strcasecmp(rdn_name, "cn") != 0) { ldb_asprintf_errstring(module->ldb, "Bad RDN (%s=) for ForeignSecurityPrincipal, should be CN=!", rdn_name); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } /* Slightly different for the foreign sids. We don't want * domain SIDs ending up there, it would cause all sorts of * pain */ sid = dom_sid_parse_talloc(msg2, (const char *)ldb_dn_get_rdn_val(msg2->dn)->data); if (!sid) { ldb_set_errstring(module->ldb, "No valid found SID in ForeignSecurityPrincipal CN!"); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } if ( ! samldb_msg_add_sid(module, msg2, "objectSid", sid)) { talloc_free(sid); return LDB_ERR_OPERATIONS_ERROR; } dom_sid = dom_sid_dup(mem_ctx, sid); if (!dom_sid) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } /* get the domain component part of the provided SID */ dom_sid->num_auths--; /* find the domain DN */ ret = gendb_search(module->ldb, mem_ctx, NULL, &dom_msgs, dom_attrs, "(&(objectSid=%s)(objectclass=domain))", ldap_encode_ndr_dom_sid(mem_ctx, dom_sid)); if (ret >= 1) { /* We don't really like the idea of foreign sids that are not foreign, but it happens */ const char *name = samdb_result_string(dom_msgs[0], "name", NULL); ldb_debug(module->ldb, LDB_DEBUG_TRACE, "NOTE (strange but valid): Adding foreign SID record with SID %s, but this domian (%s) is already in the database", dom_sid_string(mem_ctx, sid), name); } else if (ret == -1) { ldb_asprintf_errstring(module->ldb, "samldb_fill_foreignSecurityPrincipal_object: error searching for a domain with this sid: %s\n", dom_sid_string(mem_ctx, dom_sid)); talloc_free(dom_msgs); return LDB_ERR_OPERATIONS_ERROR; } /* This isn't an operation on a domain we know about, so just * check for the SID, looking for duplicates via the common * code */ ret = samldb_notice_sid(module, msg2, sid); if (ret == 0) { talloc_steal(msg, msg2); *ret_msg = msg2; } return ret; }
static int samldb_fill_user_or_computer_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg) { int ret; char *name; struct ldb_message *msg2; const char *rdn_name; TALLOC_CTX *mem_ctx = talloc_new(msg); const char *errstr; if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* build the new msg */ msg2 = ldb_msg_copy(mem_ctx, msg); if (!msg2) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } if (samdb_find_attribute(module->ldb, msg, "objectclass", "computer") != NULL) { ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateComputer)(objectclass=userTemplate))", &errstr); if (ret) { ldb_asprintf_errstring(module->ldb, "samldb_fill_user_or_computer_object: " "Error copying computer template: %s", errstr); talloc_free(mem_ctx); return ret; } /* readd user and then computer objectclasses */ ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "user"); if (ret) { talloc_free(mem_ctx); return ret; } ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "computer"); if (ret) { talloc_free(mem_ctx); return ret; } } else { ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateUser)(objectclass=userTemplate))", &errstr); if (ret) { ldb_asprintf_errstring(module->ldb, "samldb_fill_user_or_computer_object: Error copying user template: %s\n", errstr); talloc_free(mem_ctx); return ret; } /* readd user objectclass */ ret = samdb_find_or_add_value(module->ldb, msg2, "objectclass", "user"); if (ret) { talloc_free(mem_ctx); return ret; } } rdn_name = ldb_dn_get_rdn_name(msg2->dn); if (strcasecmp(rdn_name, "cn") != 0) { ldb_asprintf_errstring(module->ldb, "Bad RDN (%s=) for user/computer, should be CN=!\n", rdn_name); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } if (ldb_msg_find_element(msg2, "samAccountName") == NULL) { name = samldb_generate_samAccountName(module, mem_ctx); if (!name) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_find_or_add_attribute(module->ldb, msg2, "sAMAccountName", name); if (ret) { talloc_free(mem_ctx); return ret; } } /* TODO: useraccountcontrol: setting value 0 gives 0x200 for users */ /* Manage SID allocation, conflicts etc */ ret = samldb_handle_sid(module, mem_ctx, msg2); /* TODO: objectCategory, userAccountControl, badPwdCount, codePage, countryCode, badPasswordTime, lastLogoff, lastLogon, pwdLastSet, primaryGroupID, accountExpires, logonCount */ if (ret == 0) { *ret_msg = msg2; talloc_steal(msg, msg2); } talloc_free(mem_ctx); return ret; }
static int samldb_fill_group_object(struct ldb_module *module, const struct ldb_message *msg, struct ldb_message **ret_msg) { int ret; const char *name; struct ldb_message *msg2; const char *rdn_name; TALLOC_CTX *mem_ctx = talloc_new(msg); const char *errstr; if (!mem_ctx) { return LDB_ERR_OPERATIONS_ERROR; } /* build the new msg */ msg2 = ldb_msg_copy(mem_ctx, msg); if (!msg2) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: ldb_msg_copy failed!\n"); talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_copy_template(module->ldb, msg2, "(&(CN=TemplateGroup)(objectclass=groupTemplate))", &errstr); if (ret != 0) { talloc_free(mem_ctx); return ret; } rdn_name = ldb_dn_get_rdn_name(msg2->dn); if (strcasecmp(rdn_name, "cn") != 0) { ldb_debug(module->ldb, LDB_DEBUG_FATAL, "samldb_fill_group_object: Bad RDN (%s) for group!\n", rdn_name); talloc_free(mem_ctx); return LDB_ERR_CONSTRAINT_VIOLATION; } /* Generate a random name, if no samAccountName was supplied */ if (ldb_msg_find_element(msg2, "samAccountName") == NULL) { name = samldb_generate_samAccountName(module, mem_ctx); if (!name) { talloc_free(mem_ctx); return LDB_ERR_OPERATIONS_ERROR; } ret = samdb_find_or_add_attribute(module->ldb, msg2, "sAMAccountName", name); if (ret) { talloc_free(mem_ctx); return ret; } } /* Manage SID allocation, conflicts etc */ ret = samldb_handle_sid(module, mem_ctx, msg2); if (ret == LDB_SUCCESS) { talloc_steal(msg, msg2); *ret_msg = msg2; } talloc_free(mem_ctx); return ret; }