/* * @brief Decrypt all the secret attributes on an ldb_message * * Decrypt all the secret attributes on an ldb_message. Any secret attributes * are removed from message and decrypted copies of the attributes added. * In the event of an error the contents of the message will be inconsistent. * * @param ldb ldb context, to allow logging. * @param msg The ldb_message to have it's secret attributes encrypted. * @param data The context data for this module. * * @returns ldb status code * LDB_SUCESS If the value was successfully encrypted * LDB_ERR_OPERATIONS_ERROR If there was an error. */ static int decrypt_secret_attributes(struct ldb_context *ldb, struct ldb_message *msg, struct es_data *data) { int i, ret; if (ldb_dn_is_special(msg->dn)) { return LDB_SUCCESS; } for (i = 0; i < num_secret_attributes; i++) { struct ldb_message_element *el = ldb_msg_find_element(msg, secret_attributes[i]); if (el != NULL) { const int flags = el->flags; struct ldb_message_element* dec = decrypt_element(&ret, msg->elements, ldb, el, data); if (ret != LDB_SUCCESS) { return ret; } ldb_msg_remove_element(msg, el); ret = ldb_msg_add(msg, dec, flags); if (ret != LDB_SUCCESS) { return ret; } } } return LDB_SUCCESS; }
static WERROR dsdb_convert_object_ex(struct ldb_context *ldb, const struct dsdb_schema *schema, const struct drsuapi_DsReplicaObjectListItemEx *in, const DATA_BLOB *gensec_skey, TALLOC_CTX *mem_ctx, struct dsdb_extended_replicated_object *out) { NTSTATUS nt_status; WERROR status; uint32_t i; struct ldb_message *msg; struct replPropertyMetaDataBlob *md; struct ldb_val guid_value; NTTIME whenChanged = 0; time_t whenChanged_t; const char *whenChanged_s; const char *rdn_name = NULL; const struct ldb_val *rdn_value = NULL; const struct dsdb_attribute *rdn_attr = NULL; uint32_t rdn_attid; struct drsuapi_DsReplicaAttribute *name_a = NULL; struct drsuapi_DsReplicaMetaData *name_d = NULL; struct replPropertyMetaData1 *rdn_m = NULL; struct dom_sid *sid = NULL; uint32_t rid = 0; int ret; if (!in->object.identifier) { return WERR_FOOBAR; } if (!in->object.identifier->dn || !in->object.identifier->dn[0]) { return WERR_FOOBAR; } if (in->object.attribute_ctr.num_attributes != 0 && !in->meta_data_ctr) { return WERR_FOOBAR; } if (in->object.attribute_ctr.num_attributes != in->meta_data_ctr->count) { return WERR_FOOBAR; } sid = &in->object.identifier->sid; if (sid->num_auths > 0) { rid = sid->sub_auths[sid->num_auths - 1]; } msg = ldb_msg_new(mem_ctx); W_ERROR_HAVE_NO_MEMORY(msg); msg->dn = ldb_dn_new(msg, ldb, in->object.identifier->dn); W_ERROR_HAVE_NO_MEMORY(msg->dn); rdn_name = ldb_dn_get_rdn_name(msg->dn); rdn_attr = dsdb_attribute_by_lDAPDisplayName(schema, rdn_name); if (!rdn_attr) { return WERR_FOOBAR; } rdn_attid = rdn_attr->attributeID_id; rdn_value = ldb_dn_get_rdn_val(msg->dn); msg->num_elements = in->object.attribute_ctr.num_attributes; msg->elements = talloc_array(msg, struct ldb_message_element, msg->num_elements); W_ERROR_HAVE_NO_MEMORY(msg->elements); md = talloc(mem_ctx, struct replPropertyMetaDataBlob); W_ERROR_HAVE_NO_MEMORY(md); md->version = 1; md->reserved = 0; md->ctr.ctr1.count = in->meta_data_ctr->count; md->ctr.ctr1.reserved = 0; md->ctr.ctr1.array = talloc_array(mem_ctx, struct replPropertyMetaData1, md->ctr.ctr1.count + 1); /* +1 because of the RDN attribute */ W_ERROR_HAVE_NO_MEMORY(md->ctr.ctr1.array); for (i=0; i < in->meta_data_ctr->count; i++) { struct drsuapi_DsReplicaAttribute *a; struct drsuapi_DsReplicaMetaData *d; struct replPropertyMetaData1 *m; struct ldb_message_element *e; int j; a = &in->object.attribute_ctr.attributes[i]; d = &in->meta_data_ctr->meta_data[i]; m = &md->ctr.ctr1.array[i]; e = &msg->elements[i]; for (j=0; j<a->value_ctr.num_values; j++) { status = drsuapi_decrypt_attribute(a->value_ctr.values[j].blob, gensec_skey, rid, a); W_ERROR_NOT_OK_RETURN(status); } status = dsdb_attribute_drsuapi_to_ldb(ldb, schema, a, msg->elements, e); if (!NT_STATUS_IS_OK(status) && a->value_ctr.num_values == 0) { /* w2k8-r2 occasionally sends bogus empty attributes with rubbish attribute IDs. The only think we can do is discard these */ DEBUG(0,(__location__ ": Discarding bogus empty DsReplicaAttribute with attid 0x%x\n", a->attid)); ZERO_STRUCTP(e); continue; } W_ERROR_NOT_OK_RETURN(status); m->attid = a->attid; m->version = d->version; m->originating_change_time = d->originating_change_time; m->originating_invocation_id = d->originating_invocation_id; m->originating_usn = d->originating_usn; m->local_usn = 0; if (d->originating_change_time > whenChanged) { whenChanged = d->originating_change_time; } if (a->attid == DRSUAPI_ATTRIBUTE_name) { name_a = a; name_d = d; rdn_m = &md->ctr.ctr1.array[md->ctr.ctr1.count]; } } /* delete any empty elements */ for (i=0; i < msg->num_elements; i++) { if (msg->elements[i].name == NULL) { ldb_msg_remove_element(msg, &msg->elements[i]); i--; } } if (rdn_m) { struct ldb_message_element *el; el = ldb_msg_find_element(msg, rdn_attr->lDAPDisplayName); if (!el) { ret = ldb_msg_add_value(msg, rdn_attr->lDAPDisplayName, rdn_value, NULL); if (ret != LDB_SUCCESS) { return WERR_FOOBAR; } } else { if (el->num_values != 1) { DEBUG(0,(__location__ ": Unexpected num_values=%u\n", el->num_values)); return WERR_FOOBAR; } if (!ldb_val_equal_exact(&el->values[0], rdn_value)) { DEBUG(0,(__location__ ": RDN value changed? '%*.*s' '%*.*s'\n", (int)el->values[0].length, (int)el->values[0].length, el->values[0].data, (int)rdn_value->length, (int)rdn_value->length, rdn_value->data)); return WERR_FOOBAR; } } rdn_m->attid = rdn_attid; rdn_m->version = name_d->version; rdn_m->originating_change_time = name_d->originating_change_time; rdn_m->originating_invocation_id = name_d->originating_invocation_id; rdn_m->originating_usn = name_d->originating_usn; rdn_m->local_usn = 0; md->ctr.ctr1.count++; } whenChanged_t = nt_time_to_unix(whenChanged); whenChanged_s = ldb_timestring(msg, whenChanged_t); W_ERROR_HAVE_NO_MEMORY(whenChanged_s); nt_status = GUID_to_ndr_blob(&in->object.identifier->guid, msg, &guid_value); if (!NT_STATUS_IS_OK(nt_status)) { return ntstatus_to_werror(nt_status); } out->msg = msg; out->guid_value = guid_value; out->when_changed = whenChanged_s; out->meta_data = md; return WERR_OK; }
/** \details Set a list of properties on a message \param mem_ctx pointer to the memory context \param message_object pointer to the openchangedb message object \param row pointer to the SRow structure holding the array of properties to set on the message \return MAPI_E_SUCCESS on success, otherwise MAPI errors. */ _PUBLIC_ enum MAPISTATUS openchangedb_message_set_properties(TALLOC_CTX *mem_ctx, void *message_object, struct SRow *row) { struct openchangedb_message *msg = (struct openchangedb_message *) message_object; struct ldb_message *message; struct ldb_message_element *element; char *PidTagAttr = NULL; struct SPropValue value; char *str_value; int i; bool tofree = false; DEBUG(5, ("openchangedb_message_set_properties\n")); /* Sanity checks */ OPENCHANGE_RETVAL_IF(!msg, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!row, MAPI_E_NOT_INITIALIZED, NULL); /* Get results from correct location */ switch (msg->status) { case OPENCHANGEDB_MESSAGE_CREATE: OPENCHANGE_RETVAL_IF(!msg->msg, MAPI_E_NOT_INITIALIZED, NULL); message = msg->msg; break; case OPENCHANGEDB_MESSAGE_OPEN: OPENCHANGE_RETVAL_IF(!msg->res, MAPI_E_NOT_INITIALIZED, NULL); OPENCHANGE_RETVAL_IF(!msg->res->count, MAPI_E_NOT_INITIALIZED, NULL); message = msg->res->msgs[0]; break; default: return MAPI_E_INVALID_PARAMETER; } for (i = 0; i < row->cValues; i++) { tofree = false; value = row->lpProps[i]; switch (value.ulPropTag) { case PR_DEPTH: case PR_SOURCE_KEY: case PR_PARENT_SOURCE_KEY: case PR_CHANGE_KEY: DEBUG(5, ("Ignored attempt to set handled property %.8x\n", value.ulPropTag)); break; default: /* Convert proptag into PidTag attribute */ PidTagAttr = (char *) openchangedb_property_get_attribute(value.ulPropTag); if (!PidTagAttr) { PidTagAttr = talloc_asprintf(mem_ctx, "%.8x", value.ulPropTag); tofree = true; } str_value = openchangedb_set_folder_property_data((TALLOC_CTX *)message, &value); if (!str_value) { DEBUG(5, ("Ignored property of unhandled type %.4x\n", (value.ulPropTag & 0xFFFF))); continue; } else { element = ldb_msg_find_element(message, PidTagAttr); if (!element) { /* Case where the element doesn't exist */ ldb_msg_add_string(message, PidTagAttr, str_value); message->elements[message->num_elements - 1].flags = LDB_FLAG_MOD_ADD; } else { switch (msg->status) { case OPENCHANGEDB_MESSAGE_CREATE: ldb_msg_remove_element(message, element); ldb_msg_add_string(message, PidTagAttr, str_value); message->elements[message->num_elements - 1].flags = LDB_FLAG_MOD_ADD; break; case OPENCHANGEDB_MESSAGE_OPEN: if (element->flags == LDB_FLAG_MOD_ADD) { ldb_msg_remove_element(message, element); ldb_msg_add_string(message, PidTagAttr, str_value); message->elements[message->num_elements - 1].flags = LDB_FLAG_MOD_ADD; } else { ldb_msg_remove_element(message, element); ldb_msg_add_string(message, PidTagAttr, str_value); message->elements[message->num_elements - 1].flags = LDB_FLAG_MOD_REPLACE; } break; } } } if (tofree == true) { talloc_free((char *)PidTagAttr); } break; } } DEBUG(5, ("openchangedb_message_set_properties end\n")); return MAPI_E_SUCCESS; }