Esempio n. 1
0
/*
 * @brief Decrypt an attribute value.
 *
 * Returns a decrypted copy of the value, the original value is left intact.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully decrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context the will own the memory allocated
 * @param ldb  ldb context, to allow logging.
 * @param val  The ldb value to decrypt, not altered or freed
 * @param data The context data for this module.
 *
 * @return The decrypted ldb_val, or data_blob_null if there was an error.
 */
static struct ldb_val decrypt_value(int *err,
				    TALLOC_CTX *ctx,
				    struct ldb_context *ldb,
				    const struct ldb_val val,
				    const struct es_data *data)
{

	struct ldb_val dec;

	struct EncryptedSecret es;
	struct PlaintextSecret ps = { data_blob_null};
	int rc;
	TALLOC_CTX *frame = talloc_stackframe();

	rc = ndr_pull_struct_blob(&val,
				  frame,
				  &es,
				  (ndr_pull_flags_fn_t)
					ndr_pull_EncryptedSecret);
	if(!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_asprintf_errstring(ldb,
				       "Error(%d)  unpacking encrypted secret, "
				       "data possibly corrupted or altered\n",
				       rc);
		*err = LDB_ERR_OPERATIONS_ERROR;
		TALLOC_FREE(frame);
		return data_blob_null;
	}
	if (!check_header(&es)) {
		/*
		* Header is invalid so can't be an encrypted value
		*/
		ldb_set_errstring(ldb, "Invalid EncryptedSecrets header\n");
		*err = LDB_ERR_OPERATIONS_ERROR;
		return data_blob_null;
	}
#ifdef BUILD_WITH_GNUTLS_AEAD
	gnutls_decrypt_aead(err, frame, ldb, &es, &ps, data);
#elif defined BUILD_WITH_SAMBA_AES_GCM
	samba_decrypt_aead(err, frame, ldb, &es, &ps, data);
#endif

	if (*err != LDB_SUCCESS) {
		TALLOC_FREE(frame);
		return data_blob_null;
	}

	dec = data_blob_talloc(ctx,
			       ps.cleartext.data,
			       ps.cleartext.length);
	if (dec.data == NULL) {
		TALLOC_FREE(frame);
		ldb_set_errstring(ldb, "Out of memory, copying value\n");
		*err = LDB_ERR_OPERATIONS_ERROR;
		return data_blob_null;
	}

	TALLOC_FREE(frame);
	return dec;
}
Esempio n. 2
0
/*
 * @brief Encrypt all the values on an ldb_message_element
 *
 * Returns a copy of the original attribute with all values encrypted
 * by encrypt_value(), the original attribute is left intact.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully encrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context the will own the memory allocated
 *             for the new ldb_message_element.
 * @param ldb  ldb context, to allow logging.
 * @param el   The ldb_message_elemen to encrypt, not altered or freed
 * @param data The context data for this module.
 *
 * @return Pointer encrypted lsb_message_element, will be NULL if there was
 *         an error.
 */
static struct ldb_message_element *encrypt_element(
	int *err,
	TALLOC_CTX *ctx,
	struct ldb_context *ldb,
	const struct ldb_message_element *el,
	const struct es_data *data)
{
	struct ldb_message_element* enc;
	int i;

	enc = talloc_zero(ctx, struct ldb_message_element);
	if (enc == NULL) {
		ldb_set_errstring(ldb,
				  "Out of memory, allocating ldb_message_"
				  "element\n");
		*err = LDB_ERR_OPERATIONS_ERROR;
		return NULL;
	}

	enc->flags	= el->flags;
	enc->num_values	= el->num_values;
	enc->values	= talloc_array(enc, struct ldb_val, enc->num_values);
	if (enc->values == NULL) {
		TALLOC_FREE(enc);
		ldb_set_errstring(ldb,
				  "Out of memory, allocating values array\n");
		*err = LDB_ERR_OPERATIONS_ERROR;
		return NULL;
	}

	enc->name = talloc_strdup(enc, el->name);
	if (enc->name == NULL) {
		TALLOC_FREE(enc);
		ldb_set_errstring(ldb,
				  "Out of memory, copying element name\n");
		*err = LDB_ERR_OPERATIONS_ERROR;
		return NULL;
	}

	for (i = 0; i < el->num_values; i++) {
		enc->values[i] =
			encrypt_value(
				err,
				enc->values,
				ldb,
				el->values[i],
				data);
		if (*err != LDB_SUCCESS) {
			TALLOC_FREE(enc);
			return NULL;
		}
	}
	return enc;
}
Esempio n. 3
0
/*
 * @brief Decrypt all the encrypted values on an ldb_message_element
 *
 * Returns a copy of the original attribute with all values decrypted by
 * decrypt_value(), the original attribute is left intact.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully encrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context the will own the memory allocated
 *             for the new ldb_message_element.
 * @param ldb  ldb context, to allow logging.
 * @param el   The ldb_message_elemen to decrypt, not altered or freed
 * @param data The context data for this module.
 *
 * @return Pointer decrypted lsb_message_element, will be NULL if there was
 *         an error.
 */
static struct ldb_message_element *decrypt_element(
	int *err,
	TALLOC_CTX *ctx,
	struct ldb_context *ldb,
	struct ldb_message_element* el,
	struct es_data *data)
{
	int i;
	struct ldb_message_element* dec =
		talloc_zero(ctx, struct ldb_message_element);

	*err = LDB_SUCCESS;
	if (dec == NULL) {
		ldb_set_errstring(ldb,
				  "Out of memory, allocating "
				  "ldb_message_element\n");
		*err = LDB_ERR_OPERATIONS_ERROR;
		return NULL;
	}
	dec->num_values = el->num_values;

	dec->values = talloc_array(dec, struct ldb_val, dec->num_values);
	if (dec->values == NULL) {
		TALLOC_FREE(dec);
		ldb_set_errstring(ldb,
				  "Out of memory, allocating values array\n");
		*err = LDB_ERR_OPERATIONS_ERROR;
		return NULL;
	}

	dec->name = talloc_strdup(dec, el->name);
	if (dec->name == NULL) {
		TALLOC_FREE(dec);
		ldb_set_errstring(ldb, "Out of memory, copying element name\n");
		*err = LDB_ERR_OPERATIONS_ERROR;
		return NULL;
	}

	for (i = 0; i < el->num_values; i++) {
		dec->values[i] =
			decrypt_value(err,
				      el->values,
				      ldb,
				      el->values[i],
				      data);
		if (*err != LDB_SUCCESS) {
			TALLOC_FREE(dec);
			return NULL;
		}
	}
	return dec;
}
Esempio n. 4
0
/*
  delete a record
*/
static int lldb_delete(struct lldb_context *lldb_ac)
{
	struct ldb_context *ldb;
	struct lldb_private *lldb = lldb_ac->lldb;
	struct ldb_module *module = lldb_ac->module;
	struct ldb_request *req = lldb_ac->req;
	char *dnstr;
	int ret;

	ldb = ldb_module_get_ctx(module);

	ldb_request_set_state(req, LDB_ASYNC_PENDING);

	dnstr = ldb_dn_alloc_linearized(lldb_ac, req->op.del.dn);

	ret = ldap_delete_ext(lldb->ldap, dnstr,
			      NULL,
			      NULL,
			      &lldb_ac->msgid);

	if (ret != LDAP_SUCCESS) {
		ldb_set_errstring(ldb, ldap_err2string(ret));
	}

	return lldb_ldap_to_ldb(ret);
}
Esempio n. 5
0
/*
  modify a record
*/
static int lldb_modify(struct lldb_context *lldb_ac)
{
	struct ldb_context *ldb;
	struct lldb_private *lldb = lldb_ac->lldb;
	struct ldb_module *module = lldb_ac->module;
	struct ldb_request *req = lldb_ac->req;
	LDAPMod **mods;
	char *dn;
	int ret;

	ldb = ldb_module_get_ctx(module);

	ldb_request_set_state(req, LDB_ASYNC_PENDING);

	mods = lldb_msg_to_mods(lldb_ac, req->op.mod.message, 1);
	if (mods == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	dn = ldb_dn_alloc_linearized(lldb_ac, req->op.mod.message->dn);
	if (dn == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ret = ldap_modify_ext(lldb->ldap, dn, mods,
			      NULL,
			      NULL,
			      &lldb_ac->msgid);

	if (ret != LDAP_SUCCESS) {
		ldb_set_errstring(ldb, ldap_err2string(ret));
	}

	return lldb_ldap_to_ldb(ret);
}
Esempio n. 6
0
/*
  check special dn's have valid attributes
  currently only @ATTRIBUTES is checked
*/
static int ltdb_check_special_dn(struct ldb_module *module,
				 const struct ldb_message *msg)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	unsigned int i, j;

	if (! ldb_dn_is_special(msg->dn) ||
	    ! ldb_dn_check_special(msg->dn, LTDB_ATTRIBUTES)) {
		return LDB_SUCCESS;
	}

	/* we have @ATTRIBUTES, let's check attributes are fine */
	/* should we check that we deny multivalued attributes ? */
	for (i = 0; i < msg->num_elements; i++) {
		if (ldb_attr_cmp(msg->elements[i].name, "distinguishedName") == 0) continue;

		for (j = 0; j < msg->elements[i].num_values; j++) {
			if (ltdb_check_at_attributes_values(&msg->elements[i].values[j]) != 0) {
				ldb_set_errstring(ldb, "Invalid attribute value in an @ATTRIBUTES entry");
				return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
			}
		}
	}

	return LDB_SUCCESS;
}
Esempio n. 7
0
/*
  we've made a modification to a dn - possibly reindex and
  update sequence number
*/
static int ltdb_modified(struct ldb_module *module, struct ldb_dn *dn)
{
	int ret = LDB_SUCCESS;
	struct ltdb_private *ltdb = talloc_get_type(ldb_module_get_private(module), struct ltdb_private);

	/* only allow modifies inside a transaction, otherwise the
	 * ldb is unsafe */
	if (ltdb->in_transaction == 0) {
		ldb_set_errstring(ldb_module_get_ctx(module), "ltdb modify without transaction");
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (ldb_dn_is_special(dn) &&
	    (ldb_dn_check_special(dn, LTDB_INDEXLIST) ||
	     ldb_dn_check_special(dn, LTDB_ATTRIBUTES)) ) {
		ret = ltdb_reindex(module);
	}

	/* If the modify was to a normal record, or any special except @BASEINFO, update the seq number */
	if (ret == LDB_SUCCESS &&
	    !(ldb_dn_is_special(dn) &&
	      ldb_dn_check_special(dn, LTDB_BASEINFO)) ) {
		ret = ltdb_increase_sequence_number(module);
	}

	/* If the modify was to @OPTIONS, reload the cache */
	if (ret == LDB_SUCCESS &&
	    ldb_dn_is_special(dn) &&
	    (ldb_dn_check_special(dn, LTDB_OPTIONS)) ) {
		ret = ltdb_cache_reload(module);
	}

	return ret;
}
Esempio n. 8
0
/* search the domain related to the provided dn
   allocate a new RID for the domain
   return the new sid string
*/
static int samldb_get_new_sid(struct ldb_module *module, 
			      TALLOC_CTX *mem_ctx, struct ldb_dn *obj_dn,
			      struct dom_sid **sid)
{
	const char * const attrs[2] = { "objectSid", NULL };
	struct ldb_result *res = NULL;
	struct ldb_dn *dom_dn;
	int ret;
	struct dom_sid *dom_sid;

	/* get the domain component part of the provided dn */

	dom_dn = samldb_search_domain(module, mem_ctx, obj_dn);
	if (dom_dn == NULL) {
		ldb_asprintf_errstring(module->ldb,
					"Invalid dn (%s) not child of a domain object!\n",
					ldb_dn_get_linearized(obj_dn));
		return LDB_ERR_CONSTRAINT_VIOLATION;
	}

	/* find the domain sid */

	ret = ldb_search(module->ldb, dom_dn, LDB_SCOPE_BASE, "objectSid=*", attrs, &res);
	if (ret != LDB_SUCCESS) {
		ldb_asprintf_errstring(module->ldb,
					"samldb_get_new_sid: error retrieving domain sid from %s: %s!\n",
					ldb_dn_get_linearized(dom_dn),
					ldb_errstring(module->ldb));
		talloc_free(res);
		return ret;
	}

	if (res->count != 1) {
		ldb_asprintf_errstring(module->ldb,
					"samldb_get_new_sid: error retrieving domain sid from %s: not found!\n",
					ldb_dn_get_linearized(dom_dn));
		talloc_free(res);
		return LDB_ERR_CONSTRAINT_VIOLATION;
	}

	dom_sid = samdb_result_dom_sid(res, res->msgs[0], "objectSid");
	if (dom_sid == NULL) {
		ldb_set_errstring(module->ldb, "samldb_get_new_sid: error parsing domain sid!\n");
		talloc_free(res);
		return LDB_ERR_CONSTRAINT_VIOLATION;
	}

	/* allocate a new Rid for the domain */
	ret = samldb_allocate_next_rid(module, mem_ctx, dom_dn, dom_sid, sid);
	if (ret != 0) {
		ldb_debug(module->ldb, LDB_DEBUG_FATAL, "Failed to increment nextRid of %s: %s\n", ldb_dn_get_linearized(dom_dn), ldb_errstring(module->ldb));
		talloc_free(res);
		return ret;
	}

	talloc_free(res);

	return ret;
}
Esempio n. 9
0
/*
 * @brief Get the directory containing the key files.
 *
 * @param ctx talloc memory context that will own the return value
 * @param ldb ldb context, to allow logging
 *
 * @return zero terminated string, the directory containing the key file
 *         allocated on ctx.
 *
 */
static const char* get_key_directory(TALLOC_CTX *ctx, struct ldb_context *ldb)
{

	const char *sam_ldb_path = NULL;
	const char *private_dir  = NULL;
	char *p = NULL;


	/*
	 * Work out where *our* key file is. It must be in
	 * the same directory as sam.ldb
	 */
	sam_ldb_path = ldb_get_opaque(ldb, "ldb_url");
	if (sam_ldb_path == NULL) {
		ldb_set_errstring(ldb, "Unable to get ldb_url\n");
		return NULL;
	}

	if (strncmp("tdb://", sam_ldb_path, 6) == 0) {
		sam_ldb_path += 6;
	}
	private_dir = talloc_strdup(ctx, sam_ldb_path);
	if (private_dir == NULL) {
		ldb_set_errstring(ldb,
				  "Out of memory building encrypted "
				  "secrets key\n");
		return NULL;
	}

	p = strrchr(private_dir, '/');
	if (p != NULL) {
		*p = '\0';
	} else {
		private_dir = talloc_strdup(ctx, ".");
	}

	return private_dir;
}
Esempio n. 10
0
/*
  rename a record
*/
static int lldb_rename(struct lldb_context *lldb_ac)
{
	struct ldb_context *ldb;
	struct lldb_private *lldb = lldb_ac->lldb;
	struct ldb_module *module = lldb_ac->module;
	struct ldb_request *req = lldb_ac->req;
	const char *rdn_name;
	const struct ldb_val *rdn_val;
	char *old_dn;
	char *newrdn;
	char *parentdn;
	int ret;

	ldb = ldb_module_get_ctx(module);

	ldb_request_set_state(req, LDB_ASYNC_PENDING);

	old_dn = ldb_dn_alloc_linearized(lldb_ac, req->op.rename.olddn);
	if (old_dn == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	rdn_name = ldb_dn_get_rdn_name(req->op.rename.newdn);
	rdn_val = ldb_dn_get_rdn_val(req->op.rename.newdn);

	if ((rdn_name != NULL) && (rdn_val != NULL)) {
		newrdn = talloc_asprintf(lldb_ac, "%s=%s", rdn_name,
					 rdn_val->length > 0 ? ldb_dn_escape_value(lldb, *rdn_val) : "");
	} else {
		newrdn = talloc_strdup(lldb_ac, "");
	}
	if (!newrdn) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	parentdn = ldb_dn_alloc_linearized(lldb_ac, ldb_dn_get_parent(lldb_ac, req->op.rename.newdn));
	if (!parentdn) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ret = ldap_rename(lldb->ldap, old_dn, newrdn, parentdn,
			  1, NULL, NULL,
			  &lldb_ac->msgid);

	if (ret != LDAP_SUCCESS) {
		ldb_set_errstring(ldb, ldap_err2string(ret));
	}

	return lldb_ldap_to_ldb(ret);
}
Esempio n. 11
0
/*
  log a message, and set the ldb error string to the same message
*/
void ldb_debug_set(struct ldb_context *ldb, enum ldb_debug_level level, 
		   const char *fmt, ...)
{
	va_list ap;
	char *msg;
	va_start(ap, fmt);
	msg = talloc_vasprintf(ldb, fmt, ap);
	va_end(ap);
	if (msg != NULL) {
		ldb_set_errstring(ldb, msg);
		ldb_debug(ldb, level, "%s", msg);
	}
	talloc_free(msg);
}
Esempio n. 12
0
/*
 * @brief Create an new EncryptedSecret owned by the supplied talloc context.
 *
 * Create a new encrypted secret and initialise the header.
 *
 * @param ldb ldb context, to allow logging.
 * @param ctx The talloc memory context that will own the new EncryptedSecret
 *
 * @return pointer to the new encrypted secret, or NULL if there was an error
 */
static struct EncryptedSecret *makeEncryptedSecret(struct ldb_context *ldb,
						   TALLOC_CTX *ctx)
{
	struct EncryptedSecret *es = NULL;

	es = talloc_zero_size(ctx, sizeof(struct EncryptedSecret));
	if (es == NULL) {
		ldb_set_errstring(ldb,
				  "Out of memory, allocating "
				   "struct EncryptedSecret\n");
		return NULL;
	}
	es->header.magic     = ENCRYPTED_SECRET_MAGIC_VALUE;
	es->header.version   = SECRET_ATTRIBUTE_VERSION;
	es->header.algorithm = SECRET_ENCRYPTION_ALGORITHM;
	es->header.flags     = 0;
	return es;
}
Esempio n. 13
0
/* Create a generic request context. */
struct map_context *map_init_context(struct ldb_module *module,
					struct ldb_request *req)
{
	struct ldb_context *ldb;
	struct map_context *ac;

	ldb = ldb_module_get_ctx(module);

	ac = talloc_zero(req, struct map_context);
	if (ac == NULL) {
		ldb_set_errstring(ldb, "Out of Memory");
		return NULL;
	}

	ac->module = module;
	ac->req = req;

	return ac;
}
/* deny instancetype modification */
static int instancetype_mod(struct ldb_module *module, struct ldb_request *req)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct ldb_message_element *el;

	/* do not manipulate our control entries */
	if (ldb_dn_is_special(req->op.mod.message->dn)) {
		return ldb_next_request(module, req);
	}

	ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_mod\n");

	el = ldb_msg_find_element(req->op.mod.message, "instanceType");
	if (el != NULL) {
		/* Except to allow dbcheck to fix things, this must never be modified */
		if (!ldb_request_get_control(req, DSDB_CONTROL_DBCHECK)) {
			ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute can never be changed!");
			return LDB_ERR_CONSTRAINT_VIOLATION;
		}
	}
	return ldb_next_request(module, req);
}
Esempio n. 15
0
static int inject_extended_dn_out(struct ldb_reply *ares,
				  struct ldb_context *ldb,
				  int type,
				  bool remove_guid,
				  bool remove_sid)
{
	int ret;
	const DATA_BLOB *guid_blob;
	const DATA_BLOB *sid_blob;

	guid_blob = ldb_msg_find_ldb_val(ares->message, "objectGUID");
	sid_blob = ldb_msg_find_ldb_val(ares->message, "objectSID");

	if (!guid_blob) {
		ldb_set_errstring(ldb, "Did not find objectGUID to inject into extended DN");
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ret = ldb_dn_set_extended_component(ares->message->dn, "GUID", guid_blob);
	if (ret != LDB_SUCCESS) {
		return ret;
	}
	if (sid_blob) {
		ret = ldb_dn_set_extended_component(ares->message->dn, "SID", sid_blob);
		if (ret != LDB_SUCCESS) {
			return ret;
		}
	}

	if (remove_guid) {
		ldb_msg_remove_attr(ares->message, "objectGUID");
	}

	if (sid_blob && remove_sid) {
		ldb_msg_remove_attr(ares->message, "objectSID");
	}

	return LDB_SUCCESS;
}
Esempio n. 16
0
/*
 * @brief Allocate and populate a data blob with a PlaintextSecret structure.
 *
 * Allocate a new data blob and populate it with a serialised PlaintextSecret,
 * containing the ldb_val
 *
 * @param ctx The talloc memory context that will own the allocated memory.
 * @param ldb ldb context, to allow logging.
 * @param val The ldb value to serialise.
 *
 * @return The populated data blob or data_blob_null if there was an error.
 */
static DATA_BLOB makePlainText(TALLOC_CTX *ctx,
			       struct ldb_context *ldb,
			       const struct ldb_val val)
{
	struct PlaintextSecret ps = { .cleartext = data_blob_null};
	DATA_BLOB pt = data_blob_null;
	int rc;

	ps.cleartext.length = val.length;
	ps.cleartext.data   = val.data;

	rc = ndr_push_struct_blob(&pt,
				  ctx,
				  &ps,
				  (ndr_push_flags_fn_t)
					ndr_push_PlaintextSecret);
	if (!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_set_errstring(ldb,
				  "Unable to ndr push PlaintextSecret\n");
		return data_blob_null;
	}
	return pt;
}
Esempio n. 17
0
static int samba_dsdb_init(struct ldb_module *module)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	int ret, len, i;
	TALLOC_CTX *tmp_ctx = talloc_new(module);
	struct ldb_result *res;
	struct ldb_message *rootdse_msg = NULL, *partition_msg;
	struct ldb_dn *samba_dsdb_dn, *partition_dn;
	struct ldb_module *backend_module, *module_chain;
	const char **final_module_list, **reverse_module_list;
	/*
	  Add modules to the list to activate them by default
	  beware often order is important

	  Some Known ordering constraints:
	  - rootdse must be first, as it makes redirects from "" -> cn=rootdse
	  - extended_dn_in must be before objectclass.c, as it resolves the DN
	  - objectclass must be before password_hash and samldb since these LDB
	    modules require the expanded "objectClass" list
	  - objectclass must be before descriptor and acl, as both assume that
	    objectClass values are sorted
	  - objectclass_attrs must be behind operational in order to see all
	    attributes (the operational module protects and therefore
	    suppresses per default some important ones)
	  - partition must be last
	  - each partition has its own module list then

	  The list is presented here as a set of declarations to show the
	  stack visually - the code below then handles the creation of the list
	  based on the parameters loaded from the database.
	*/
	static const char *modules_list1[] = {"resolve_oids",
					     "rootdse",
					     "schema_load",
					     "lazy_commit",
					     "dirsync",
					     "paged_results",
					     "ranged_results",
					     "anr",
					     "server_sort",
					     "asq",
					     "extended_dn_store",
					     NULL };
	/* extended_dn_in or extended_dn_in_openldap goes here */
	static const char *modules_list1a[] = {"objectclass",
					     "descriptor",
					     "acl",
					     "aclread",
					     "samldb",
					     "password_hash",
					     "operational",
					     "instancetype",
					     "objectclass_attrs",
					     NULL };

	const char **link_modules;
	static const char *fedora_ds_modules[] = {
		"rdn_name", NULL };
	static const char *openldap_modules[] = {
		NULL };
	static const char *tdb_modules_list[] = {
		"rdn_name",
		"subtree_delete",
		"repl_meta_data",
		"subtree_rename",
		"linked_attributes",
		NULL};

	const char *extended_dn_module;
	const char *extended_dn_module_ldb = "extended_dn_out_ldb";
	const char *extended_dn_module_fds = "extended_dn_out_fds";
	const char *extended_dn_module_openldap = "extended_dn_out_openldap";
	const char *extended_dn_in_module = "extended_dn_in";

	static const char *modules_list2[] = {"show_deleted",
					      "new_partition",
					      "partition",
					      NULL };

	const char **backend_modules;
	static const char *fedora_ds_backend_modules[] = {
		"nsuniqueid", "paged_searches", "simple_dn", NULL };
	static const char *openldap_backend_modules[] = {
		"entryuuid", "simple_dn", NULL };

	static const char *samba_dsdb_attrs[] = { "backendType", NULL };
	static const char *partition_attrs[] = { "ldapBackend", NULL };
	const char *backendType, *backendUrl;
	bool use_sasl_external = false;

	if (!tmp_ctx) {
		return ldb_oom(ldb);
	}

	ret = ldb_register_samba_handlers(ldb);
	if (ret != LDB_SUCCESS) {
		talloc_free(tmp_ctx);
		return ret;
	}

	samba_dsdb_dn = ldb_dn_new(tmp_ctx, ldb, "@SAMBA_DSDB");
	if (!samba_dsdb_dn) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

	partition_dn = ldb_dn_new(tmp_ctx, ldb, DSDB_PARTITION_DN);
	if (!partition_dn) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

#define CHECK_LDB_RET(check_ret)				\
	do {							\
		if (check_ret != LDB_SUCCESS) {			\
			talloc_free(tmp_ctx);			\
			return check_ret;			\
		}						\
	} while (0)

	ret = dsdb_module_search_dn(module, tmp_ctx, &res, samba_dsdb_dn,
	                            samba_dsdb_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
	if (ret == LDB_ERR_NO_SUCH_OBJECT) {
		backendType = "ldb";
	} else if (ret == LDB_SUCCESS) {
		backendType = ldb_msg_find_attr_as_string(res->msgs[0], "backendType", "ldb");
	} else {
		talloc_free(tmp_ctx);
		return ret;
	}

	backend_modules = NULL;
	if (strcasecmp(backendType, "ldb") == 0) {
		extended_dn_module = extended_dn_module_ldb;
		link_modules = tdb_modules_list;
	} else {
		struct cli_credentials *cred;
		bool is_ldapi = false;

		ret = dsdb_module_search_dn(module, tmp_ctx, &res, partition_dn,
					    partition_attrs, DSDB_FLAG_NEXT_MODULE, NULL);
		if (ret == LDB_SUCCESS) {
			backendUrl = ldb_msg_find_attr_as_string(res->msgs[0], "ldapBackend", "ldapi://");
			if (!strncasecmp(backendUrl, "ldapi://", sizeof("ldapi://")-1)) {
				is_ldapi = true;
			}
		} else if (ret != LDB_ERR_NO_SUCH_OBJECT) {
			talloc_free(tmp_ctx);
			return ret;
		}
		if (strcasecmp(backendType, "fedora-ds") == 0) {
			link_modules = fedora_ds_modules;
			backend_modules = fedora_ds_backend_modules;
			extended_dn_module = extended_dn_module_fds;
		} else if (strcasecmp(backendType, "openldap") == 0) {
			link_modules = openldap_modules;
			backend_modules = openldap_backend_modules;
			extended_dn_module = extended_dn_module_openldap;
			extended_dn_in_module = "extended_dn_in_openldap";
			if (is_ldapi) {
				use_sasl_external = true;
			}
		} else {
			return ldb_error(ldb, LDB_ERR_OPERATIONS_ERROR, "invalid backend type");
		}
		ret = ldb_set_opaque(ldb, "readOnlySchema", (void*)1);
		if (ret != LDB_SUCCESS) {
			ldb_set_errstring(ldb, "Failed to set readOnlySchema opaque");
		}

		cred = ldb_get_opaque(ldb, "credentials");
		if (!cred || !cli_credentials_authentication_requested(cred)) {
			ret = set_ldap_credentials(ldb, use_sasl_external);
			if (ret != LDB_SUCCESS) {
				return ret;
			}
		}
	}

#define CHECK_MODULE_LIST \
	do {							\
		if (!final_module_list) {			\
			talloc_free(tmp_ctx);			\
			return ldb_oom(ldb);			\
		}						\
	} while (0)

	final_module_list = str_list_copy_const(tmp_ctx, modules_list1);
	CHECK_MODULE_LIST;

	final_module_list = str_list_add_const(final_module_list, extended_dn_in_module);
	CHECK_MODULE_LIST;

	final_module_list = str_list_append_const(final_module_list, modules_list1a);
	CHECK_MODULE_LIST;

	final_module_list = str_list_append_const(final_module_list, link_modules);
	CHECK_MODULE_LIST;

	final_module_list = str_list_add_const(final_module_list, extended_dn_module);
	CHECK_MODULE_LIST;

	final_module_list = str_list_append_const(final_module_list, modules_list2);
	CHECK_MODULE_LIST;


	ret = read_at_rootdse_record(ldb, module, tmp_ctx, &rootdse_msg, NULL);
	CHECK_LDB_RET(ret);

	partition_msg = ldb_msg_new(tmp_ctx);
	partition_msg->dn = ldb_dn_new(partition_msg, ldb, "@" DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME);

	ret = prepare_modules_line(ldb, tmp_ctx,
				   rootdse_msg,
				   partition_msg, "schemaNamingContext",
				   "schema_data", backend_modules);
	CHECK_LDB_RET(ret);

	ret = prepare_modules_line(ldb, tmp_ctx,
				   rootdse_msg,
				   partition_msg, NULL,
				   NULL, backend_modules);
	CHECK_LDB_RET(ret);

	ret = ldb_set_opaque(ldb, DSDB_OPAQUE_PARTITION_MODULE_MSG_OPAQUE_NAME, partition_msg);
	CHECK_LDB_RET(ret);

	talloc_steal(ldb, partition_msg);

	/* Now prepare the module chain.  Oddly, we must give it to ldb_load_modules_list in REVERSE */
	for (len = 0; final_module_list[len]; len++) { /* noop */};

	reverse_module_list = talloc_array(tmp_ctx, const char *, len+1);
	if (!reverse_module_list) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}
	for (i=0; i < len; i++) {
		reverse_module_list[i] = final_module_list[(len - 1) - i];
	}
	reverse_module_list[i] = NULL;

	/* The backend (at least until the partitions module
	 * reconfigures things) is the next module in the currently
	 * loaded chain */
	backend_module = ldb_module_next(module);
	ret = ldb_module_load_list(ldb, reverse_module_list, backend_module, &module_chain);
	CHECK_LDB_RET(ret);

	talloc_free(tmp_ctx);
	/* Set this as the 'next' module, so that we effectivly append it to module chain */
	ldb_module_set_next(module, module_chain);

	return ldb_next_init(module);
}
Esempio n. 18
0
static int rdn_name_add(struct ldb_module *module, struct ldb_request *req)
{
	struct ldb_context *ldb;
	struct ldb_request *down_req;
	struct rename_context *ac;
	struct ldb_message *msg;
	struct ldb_message_element *attribute;
	const struct ldb_schema_attribute *a;
	const char *rdn_name;
	struct ldb_val rdn_val;
	int i, ret;

	ldb = ldb_module_get_ctx(module);

	/* do not manipulate our control entries */
	if (ldb_dn_is_special(req->op.add.message->dn)) {
		return ldb_next_request(module, req);
	}

	ac = talloc_zero(req, struct rename_context);
	if (ac == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ac->module = module;
	ac->req = req;

	msg = ldb_msg_copy_shallow(req, req->op.add.message);
	if (msg == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	rdn_name = ldb_dn_get_rdn_name(msg->dn);
	if (rdn_name == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}
	
	rdn_val = ldb_val_dup(msg, ldb_dn_get_rdn_val(msg->dn));
	
	/* Perhaps someone above us tried to set this? */
	if ((attribute = rdn_name_find_attribute(msg, "name")) != NULL ) {
		attribute->num_values = 0;
	}

	if (ldb_msg_add_value(msg, "name", &rdn_val, NULL) != 0) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	attribute = rdn_name_find_attribute(msg, rdn_name);

	if (!attribute) {
		if (ldb_msg_add_value(msg, rdn_name, &rdn_val, NULL) != 0) {
			return LDB_ERR_OPERATIONS_ERROR;
		}
	} else {
		a = ldb_schema_attribute_by_name(ldb, rdn_name);

		for (i = 0; i < attribute->num_values; i++) {
			ret = a->syntax->comparison_fn(ldb, msg,
					&rdn_val, &attribute->values[i]);
			if (ret == 0) {
				/* overwrite so it matches in case */
				attribute->values[i] = rdn_val;
				break;
			}
		}
		if (i == attribute->num_values) {
			char *rdn_errstring = talloc_asprintf(ac,
				"RDN mismatch on %s: %s (%.*s) should match one of:", 
				ldb_dn_get_linearized(msg->dn), rdn_name, 
				(int)rdn_val.length, (const char *)rdn_val.data);
			for (i = 0; i < attribute->num_values; i++) {
				rdn_errstring = talloc_asprintf_append(
					rdn_errstring, " (%.*s)",
					(int)attribute->values[i].length, 
					(const char *)attribute->values[i].data);
			}
			ldb_set_errstring(ldb, rdn_errstring);
			/* Match AD's error here */
			return LDB_ERR_INVALID_DN_SYNTAX;
		}
	}

	ret = ldb_build_add_req(&down_req, ldb, req,
				msg,
				req->controls,
				ac, rdn_name_add_callback,
				req);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	talloc_steal(down_req, msg);

	/* go on with the call chain */
	return ldb_next_request(module, down_req);
}
Esempio n. 19
0
static int ltdb_handle_request(struct ldb_module *module,
			       struct ldb_request *req)
{
	struct ldb_control *control_permissive;
	struct ldb_context *ldb;
	struct tevent_context *ev;
	struct ltdb_context *ac;
	struct tevent_timer *te;
	struct timeval tv;
	unsigned int i;

	ldb = ldb_module_get_ctx(module);

	control_permissive = ldb_request_get_control(req,
					LDB_CONTROL_PERMISSIVE_MODIFY_OID);

	for (i = 0; req->controls && req->controls[i]; i++) {
		if (req->controls[i]->critical &&
		    req->controls[i] != control_permissive) {
			ldb_asprintf_errstring(ldb, "Unsupported critical extension %s",
					       req->controls[i]->oid);
			return LDB_ERR_UNSUPPORTED_CRITICAL_EXTENSION;
		}
	}

	if (req->starttime == 0 || req->timeout == 0) {
		ldb_set_errstring(ldb, "Invalid timeout settings");
		return LDB_ERR_TIME_LIMIT_EXCEEDED;
	}

	ev = ldb_get_event_context(ldb);

	ac = talloc_zero(ldb, struct ltdb_context);
	if (ac == NULL) {
		ldb_oom(ldb);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ac->module = module;
	ac->req = req;

	tv.tv_sec = 0;
	tv.tv_usec = 0;
	te = tevent_add_timer(ev, ac, tv, ltdb_callback, ac);
	if (NULL == te) {
		talloc_free(ac);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (req->timeout > 0) {
		tv.tv_sec = req->starttime + req->timeout;
		tv.tv_usec = 0;
		ac->timeout_event = tevent_add_timer(ev, ac, tv,
						     ltdb_timeout, ac);
		if (NULL == ac->timeout_event) {
			talloc_free(ac);
			return LDB_ERR_OPERATIONS_ERROR;
		}
	}

	/* set a spy so that we do not try to use the request context
	 * if it is freed before ltdb_callback fires */
	ac->spy = talloc(req, struct ltdb_req_spy);
	if (NULL == ac->spy) {
		talloc_free(ac);
		return LDB_ERR_OPERATIONS_ERROR;
	}
	ac->spy->ctx = ac;

	talloc_set_destructor((TALLOC_CTX *)ac->spy, ltdb_request_destructor);

	return LDB_SUCCESS;
}
Esempio n. 20
0
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;
}
Esempio n. 21
0
/*
  construct the token groups for SAM objects from a message
*/
static int construct_token_groups(struct ldb_module *module,
				  struct ldb_message *msg, enum ldb_scope scope,
				  struct ldb_request *parent)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);;
	TALLOC_CTX *tmp_ctx = talloc_new(msg);
	unsigned int i;
	int ret;
	const char *filter;

	NTSTATUS status;

	struct dom_sid *primary_group_sid;
	const char *primary_group_string;
	const char *primary_group_dn;
	DATA_BLOB primary_group_blob;

	struct dom_sid *account_sid;
	const char *account_sid_string;
	const char *account_sid_dn;
	DATA_BLOB account_sid_blob;
	struct dom_sid *groupSIDs = NULL;
	unsigned int num_groupSIDs = 0;

	struct dom_sid *domain_sid;

	if (scope != LDB_SCOPE_BASE) {
		ldb_set_errstring(ldb, "Cannot provide tokenGroups attribute, this is not a BASE search");
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/* If it's not a user, it won't have a primaryGroupID */
	if (ldb_msg_find_element(msg, "primaryGroupID") == NULL) {
		talloc_free(tmp_ctx);
		return LDB_SUCCESS;
	}

	/* Ensure it has an objectSID too */
	account_sid = samdb_result_dom_sid(tmp_ctx, msg, "objectSid");
	if (account_sid == NULL) {
		talloc_free(tmp_ctx);
		return LDB_SUCCESS;
	}

	status = dom_sid_split_rid(tmp_ctx, account_sid, &domain_sid, NULL);
	if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_PARAMETER)) {
		talloc_free(tmp_ctx);
		return LDB_ERR_INVALID_ATTRIBUTE_SYNTAX;
	} else if (!NT_STATUS_IS_OK(status)) {
		talloc_free(tmp_ctx);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	primary_group_sid = dom_sid_add_rid(tmp_ctx,
					    domain_sid,
					    ldb_msg_find_attr_as_uint(msg, "primaryGroupID", ~0));
	if (!primary_group_sid) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

	/* only return security groups */
	filter = talloc_asprintf(tmp_ctx, "(&(objectClass=group)(groupType:1.2.840.113556.1.4.803:=%u))",
				 GROUP_TYPE_SECURITY_ENABLED);
	if (!filter) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

	primary_group_string = dom_sid_string(tmp_ctx, primary_group_sid);
	if (!primary_group_string) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

	primary_group_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", primary_group_string);
	if (!primary_group_dn) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

	primary_group_blob = data_blob_string_const(primary_group_dn);

	account_sid_string = dom_sid_string(tmp_ctx, account_sid);
	if (!account_sid_string) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

	account_sid_dn = talloc_asprintf(tmp_ctx, "<SID=%s>", account_sid_string);
	if (!account_sid_dn) {
		talloc_free(tmp_ctx);
		return ldb_oom(ldb);
	}

	account_sid_blob = data_blob_string_const(account_sid_dn);

	status = dsdb_expand_nested_groups(ldb, &account_sid_blob,
					   true, /* We don't want to add the object's SID itself,
						    it's not returend in this attribute */
					   filter,
					   tmp_ctx, &groupSIDs, &num_groupSIDs);

	if (!NT_STATUS_IS_OK(status)) {
		ldb_asprintf_errstring(ldb, "Failed to construct tokenGroups: expanding groups of SID %s failed: %s",
				       account_sid_string, nt_errstr(status));
		talloc_free(tmp_ctx);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	/* Expands the primary group - this function takes in
	 * memberOf-like values, so we fake one up with the
	 * <SID=S-...> format of DN and then let it expand
	 * them, as long as they meet the filter - so only
	 * domain groups, not builtin groups
	 */
	status = dsdb_expand_nested_groups(ldb, &primary_group_blob, false, filter,
					   tmp_ctx, &groupSIDs, &num_groupSIDs);
	if (!NT_STATUS_IS_OK(status)) {
		ldb_asprintf_errstring(ldb, "Failed to construct tokenGroups: expanding groups of SID %s failed: %s",
				       account_sid_string, nt_errstr(status));
		talloc_free(tmp_ctx);
		return LDB_ERR_OPERATIONS_ERROR;
	}

	for (i=0; i < num_groupSIDs; i++) {
		ret = samdb_msg_add_dom_sid(ldb, msg, msg, "tokenGroups", &groupSIDs[i]);
		if (ret) {
			talloc_free(tmp_ctx);
			return ret;
		}
	}

	return LDB_SUCCESS;
}
/* add_record: add instancetype attribute */
static int instancetype_add(struct ldb_module *module, struct ldb_request *req)
{
	struct ldb_context *ldb = ldb_module_get_ctx(module);
	struct ldb_request *down_req;
	struct ldb_message *msg;
	struct ldb_message_element *el;
	uint32_t instanceType;
	int ret;

	/* do not manipulate our control entries */
	if (ldb_dn_is_special(req->op.add.message->dn)) {
		return ldb_next_request(module, req);
	}

	ldb_debug(ldb, LDB_DEBUG_TRACE, "instancetype_add\n");

	el = ldb_msg_find_element(req->op.add.message, "instanceType");
	if (el != NULL) {
		if (el->num_values != 1) {
			ldb_set_errstring(ldb, "instancetype: the 'instanceType' attribute is single-valued!");
			return LDB_ERR_UNWILLING_TO_PERFORM;
		}

		instanceType = ldb_msg_find_attr_as_uint(req->op.add.message,
							 "instanceType", 0);
		if (!(instanceType & INSTANCE_TYPE_IS_NC_HEAD)) {
			/*
			 * If we have no NC add operation (no TYPE_IS_NC_HEAD)
			 * then "instanceType" can only be "0" or "TYPE_WRITE".
			 */
			if ((instanceType != 0) &&
			    ((instanceType & INSTANCE_TYPE_WRITE) == 0)) {
				ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD wasn't set, then only TYPE_WRITE or 0 are allowed!");
				return LDB_ERR_UNWILLING_TO_PERFORM;
			}
		} else {
			/*
			 * If we have a NC add operation then we need also the
			 * "TYPE_WRITE" flag in order to succeed,
			 * unless this NC is not instantiated
			*/
			if (!(instanceType & INSTANCE_TYPE_UNINSTANT) &&
			    !(instanceType & INSTANCE_TYPE_WRITE)) {
				ldb_set_errstring(ldb, "instancetype: if TYPE_IS_NC_HEAD was set, then also TYPE_WRITE is requested!");
				return LDB_ERR_UNWILLING_TO_PERFORM;
			}
		}

		/* we did only tests, so proceed with the original request */
		return ldb_next_request(module, req);
	}

	/* we have to copy the message as the caller might have it as a const */
	msg = ldb_msg_copy_shallow(req, req->op.add.message);
	if (msg == NULL) {
		return ldb_oom(ldb);
	}

	/*
	 * TODO: calculate correct instance type
	 */
	instanceType = INSTANCE_TYPE_WRITE;

	ret = samdb_msg_add_uint(ldb, msg, msg, "instanceType", instanceType);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	ret = ldb_build_add_req(&down_req, ldb, req,
				msg,
				req->controls,
				req, dsdb_next_callback,
				req);
	LDB_REQ_SET_LOCATION(down_req);
	if (ret != LDB_SUCCESS) {
		return ret;
	}

	/* go on with the call chain */
	return ldb_next_request(module, down_req);
}
Esempio n. 23
0
/*
 * Helper function converts a data blob to a gnutls_datum_t.
 * Note that this does not copy the data.
 *      So the returned value should be treated as read only.
 *      And that changes to the length of the underlying DATA_BLOB
 *      will not be reflected in the returned object.
 *
 */
static const gnutls_datum_t convert_from_data_blob(DATA_BLOB blob) {

	const gnutls_datum_t datum = {
		.size = blob.length,
		.data = blob.data,
	};
	return datum;
}

/*
 * @brief Get the gnutls algorithm needed to decrypt the EncryptedSecret
 *
 * @param ldb ldb context, to allow logging.
 * @param es  the encrypted secret
 *
 * @return The gnutls algoritm number, or 0 if there is no match.
 *
 */
static int gnutls_get_algorithm(struct ldb_context *ldb,
				struct EncryptedSecret *es) {

	switch (es->header.algorithm) {
	case ENC_SECRET_AES_128_AEAD:
		return GNUTLS_CIPHER_AES_128_GCM;
	default:
		ldb_asprintf_errstring(ldb,
				       "Unsupported encryption algorithm %d\n",
				       es->header.algorithm);
		return 0;
	}
}

/*
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully encrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context the will own the memory allocated
 * @param ldb  ldb context, to allow logging.
 * @param val  The ldb value to encrypt, not altered or freed
 * @param data The context data for this module.
 *
 * @return The encrypted ldb_val, or data_blob_null if there was an error.
 */
static struct ldb_val gnutls_encrypt_aead(int *err,
					  TALLOC_CTX *ctx,
					  struct ldb_context *ldb,
					  const struct ldb_val val,
					  const struct es_data *data)
{
	struct EncryptedSecret *es = NULL;
	struct ldb_val enc = data_blob_null;
	DATA_BLOB pt = data_blob_null;
	gnutls_aead_cipher_hd_t cipher_hnd;
	int rc;

	TALLOC_CTX *frame = talloc_stackframe();

	es = makeEncryptedSecret(ldb, frame);
	if (es == NULL) {
		goto error_exit;
	}

	pt = makePlainText(frame, ldb, val);
	if (pt.length == 0) {
		goto error_exit;
	}

	/*
	 * Set the encryption key and initialize the encryption handle.
	 */
	{
		const size_t key_size = gnutls_cipher_get_key_size(
			data->encryption_algorithm);
		gnutls_datum_t cipher_key;
		DATA_BLOB key_blob = get_key(data);

		if (key_blob.length != key_size) {
			ldb_asprintf_errstring(ldb,
					       "Invalid EncryptedSecrets key "
					       "size, expected %zu bytes and "
					       "it is %zu bytes\n",
					       key_size,
					       key_blob.length);
			goto error_exit;
		}
		cipher_key = convert_from_data_blob(key_blob);

		rc = gnutls_aead_cipher_init(&cipher_hnd,
					     data->encryption_algorithm,
					     &cipher_key);
		if (rc !=0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_aead_cipher_init failed "
					       "%s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			goto error_exit;
		}

	}

	/*
	 * Set the initialisation vector
	 */
	{
		unsigned iv_size = gnutls_cipher_get_iv_size(
			data->encryption_algorithm);
		uint8_t *iv;

		iv = talloc_zero_size(frame, iv_size);
		if (iv == NULL) {
			ldb_set_errstring(ldb,
					  "Out of memory allocating IV\n");
			goto error_exit_handle;
		}

		rc = gnutls_rnd(GNUTLS_RND_NONCE, iv, iv_size);
		if (rc !=0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_rnd failed %s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			goto error_exit_handle;
		}
		es->iv.length = iv_size;
		es->iv.data   = iv;
	}

	/*
	 * Encrypt the value.
	 */
	{
		const unsigned block_size = gnutls_cipher_get_block_size(
			data->encryption_algorithm);
		const unsigned tag_size = gnutls_cipher_get_tag_size(
			data->encryption_algorithm);
		const size_t ed_size = round_to_block_size(
			block_size,
			sizeof(struct PlaintextSecret) + val.length);
		const size_t en_size = ed_size + tag_size;
		uint8_t *ct = talloc_zero_size(frame, en_size);
		size_t el = en_size;

		if (ct == NULL) {
			ldb_set_errstring(ldb,
					  "Out of memory allocation cipher "
					  "text\n");
			goto error_exit_handle;
		}

		rc = gnutls_aead_cipher_encrypt(
			cipher_hnd,
			es->iv.data,
			es->iv.length,
			&es->header,
			sizeof(struct EncryptedSecretHeader),
			tag_size,
			pt.data,
			pt.length,
			ct,
			&el);
		if (rc !=0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_aead_cipher_encrypt '"
					       "failed %s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			*err = LDB_ERR_OPERATIONS_ERROR;
			return data_blob_null;
		}
		es->encrypted.length = el;
		es->encrypted.data   = ct;
		gnutls_aead_cipher_deinit(cipher_hnd);
	}

	rc = ndr_push_struct_blob(&enc,
				  ctx,
				  es,
				  (ndr_push_flags_fn_t)
					ndr_push_EncryptedSecret);
	if (!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_set_errstring(ldb,
				  "Unable to ndr push EncryptedSecret\n");
		goto error_exit;
	}
	TALLOC_FREE(frame);
	return enc;

error_exit_handle:
	gnutls_aead_cipher_deinit(cipher_hnd);
error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	TALLOC_FREE(frame);
	return data_blob_null;
}

/*
 * @brief Decrypt data encrypted using an aead algorithm.
 *
 * Decrypt the data in ed and insert it into ev. The data was encrypted
 * with one of the gnutls aead compatable algorithms.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully decrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  The talloc context that will own the PlaintextSecret
 * @param ldb  ldb context, to allow logging.
 * @param ev   The value to be updated with the decrypted data.
 * @param ed   The data to decrypt.
 * @param data The context data for this module.
 *
 * @return ev is updated with the unencrypted data.
 */
static void gnutls_decrypt_aead(int *err,
				TALLOC_CTX *ctx,
				struct ldb_context *ldb,
				struct EncryptedSecret *es,
				struct PlaintextSecret *ps,
				const struct es_data *data)
{

	gnutls_aead_cipher_hd_t cipher_hnd;
	DATA_BLOB pt = data_blob_null;
	const unsigned tag_size =
		gnutls_cipher_get_tag_size(es->header.algorithm);
	int rc;

	/*
	 * Get the encryption key and initialise the encryption handle
	 */
	{
		gnutls_datum_t cipher_key;
		DATA_BLOB key_blob;
		const int algorithm = gnutls_get_algorithm(ldb, es);
		const size_t key_size = gnutls_cipher_get_key_size(algorithm);
		key_blob   = get_key(data);

		if (algorithm == 0) {
			goto error_exit;
		}

		if (key_blob.length != key_size) {
			ldb_asprintf_errstring(ldb,
					       "Invalid EncryptedSecrets key "
					       "size, expected %zu bytes and "
					       "it is %zu bytes\n",
					       key_size,
					       key_blob.length);
			goto error_exit;
		}
		cipher_key = convert_from_data_blob(key_blob);

		rc = gnutls_aead_cipher_init(
			&cipher_hnd,
			algorithm,
			&cipher_key);
		if (rc != 0) {
			ldb_asprintf_errstring(ldb,
					       "gnutls_aead_cipher_init failed "
					       "%s - %s\n",
					       gnutls_strerror_name(rc),
					       gnutls_strerror(rc));
			goto error_exit;
		}
	}

	/*
	 * Decrypt and validate the encrypted value
	 */

	pt.length = es->encrypted.length;
	pt.data = talloc_zero_size(ctx, es->encrypted.length);

	if (pt.data == NULL) {
		ldb_set_errstring(ldb,
				  "Out of memory allocating plain text\n");
		goto error_exit_handle;
	}

	rc = gnutls_aead_cipher_decrypt(cipher_hnd,
					es->iv.data,
					es->iv.length,
					&es->header,
					sizeof(struct EncryptedSecretHeader),
					tag_size,
					es->encrypted.data,
					es->encrypted.length,
					pt.data,
					&pt.length);
	if (rc != 0) {
		/*
		 * Typically this will indicate that the data has been
		 * corrupted i.e. the tag comparison has failed.
		 * At the moment gnutls does not provide a separate
		 * error code to indicate this
		 */
		ldb_asprintf_errstring(ldb,
				       "gnutls_aead_cipher_decrypt failed "
				       "%s - %s. Data possibly corrupted or "
				       "altered\n",
				       gnutls_strerror_name(rc),
				       gnutls_strerror(rc));
		goto error_exit_handle;
	}
	gnutls_aead_cipher_deinit(cipher_hnd);

	rc = ndr_pull_struct_blob(&pt,
				  ctx,
				  ps,
				  (ndr_pull_flags_fn_t)
					ndr_pull_PlaintextSecret);
	if(!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_asprintf_errstring(ldb,
				       "Error(%d) unpacking decrypted data, "
				       "data possibly corrupted or altered\n",
				       rc);
		goto error_exit;
	}
	return;

error_exit_handle:
	gnutls_aead_cipher_deinit(cipher_hnd);
error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	return;
}
Esempio n. 24
0
/*
 * @brief Decrypt data encrypted using an aead algorithm.
 *
 * Decrypt the data in ed and insert it into ev. The data was encrypted
 * with the samba aes gcm implementation.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully decrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context that will own the memory allocated
 * @param ldb  ldb context, to allow logging.
 * @param ev   The value to be updated with the decrypted data.
 * @param ed   The data to decrypt.
 * @param data The context data for this module.
 *
 * @return ev is updated with the unencrypted data.
 */
static void samba_decrypt_aead(int *err,
			       TALLOC_CTX *ctx,
			       struct ldb_context *ldb,
			       struct EncryptedSecret *es,
			       struct PlaintextSecret *ps,
			       const struct es_data *data)
{
	struct aes_gcm_128_context cctx;
	DATA_BLOB pt = data_blob_null;
	DATA_BLOB key_blob = data_blob_null;
	uint8_t sig[AES_BLOCK_SIZE] = {0, };
	int rc;
	int cmp;
	TALLOC_CTX *frame = talloc_stackframe();

	/*
	 * Set the encryption key
	 */
	key_blob = get_key(data);
	if (key_blob.length != AES_BLOCK_SIZE) {
		ldb_asprintf_errstring(ldb,
				       "Invalid EncryptedSecrets key size, "
				       "expected %u bytes and is %zu bytes\n",
				       AES_BLOCK_SIZE,
				       key_blob.length);
		goto error_exit;
	}

	if (es->iv.length < AES_GCM_128_IV_SIZE) {
		ldb_asprintf_errstring(ldb,
				       "Invalid EncryptedSecrets iv size, "
				       "expected %u bytes and is %zu bytes\n",
				       AES_GCM_128_IV_SIZE,
				       es->iv.length);
		goto error_exit;
	}

	if (es->encrypted.length < AES_BLOCK_SIZE) {
		ldb_asprintf_errstring(ldb,
				       "Invalid EncryptedData size, "
				       "expected %u bytes and is %zu bytes\n",
				       AES_BLOCK_SIZE,
				       es->encrypted.length);
		goto error_exit;
	}

	pt.length = es->encrypted.length - AES_BLOCK_SIZE;
	pt.data   = talloc_zero_size(ctx, pt.length);
	if (pt.data == NULL) {
		ldb_set_errstring(ldb,
			          "Out of memory allocating space for "
				  "plain text\n");
		goto error_exit;
	}
	memcpy(pt.data, es->encrypted.data, pt.length);

	aes_gcm_128_init(&cctx, key_blob.data, es->iv.data);
	aes_gcm_128_updateA(&cctx,
		    (uint8_t *)&es->header,
		    sizeof(struct EncryptedSecretHeader));
	aes_gcm_128_updateC(&cctx, pt.data, pt.length);
	aes_gcm_128_crypt(&cctx, pt.data, pt.length);
	aes_gcm_128_digest(&cctx, sig);

	/*
	 * Check the authentication tag
	 */
	cmp = memcmp(&es->encrypted.data[pt.length], sig, AES_BLOCK_SIZE);
	if (cmp != 0) {
		ldb_set_errstring(ldb,
				  "Tag does not match, "
				  "data corrupted or altered\n");
		goto error_exit;
	}

	rc = ndr_pull_struct_blob(&pt,
				  ctx,
				  ps,
				  (ndr_pull_flags_fn_t)
					ndr_pull_PlaintextSecret);
	if(!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_asprintf_errstring(ldb,
				       "Error(%d)  unpacking decrypted data, "
				       "data possibly corrupted or altered\n",
				       rc);
		goto error_exit;
	}
	TALLOC_FREE(frame);
	return;

error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	TALLOC_FREE(frame);
	return;
}
Esempio n. 25
0
/*
 * @brief Encrypt an ldb value using an aead algorithm.
 *
 * This function uses the samba internal implementation to perform the encryption. However
 * the encrypted data and tag are stored in a manner compatible with gnutls,
 * so the gnutls aead functions can be used to decrypt and verify the data.
 *
 * @param err  Pointer to an error code, set to:
 *             LDB_SUCESS               If the value was successfully encrypted
 *             LDB_ERR_OPERATIONS_ERROR If there was an error.
 *
 * @param ctx  Talloc memory context the will own the memory allocated
 * @param ldb  ldb context, to allow logging.
 * @param val  The ldb value to encrypt, not altered or freed
 * @param data The context data for this module.
 *
 * @return The encrypted ldb_val, or data_blob_null if there was an error.
 */
static struct ldb_val samba_encrypt_aead(int *err,
					 TALLOC_CTX *ctx,
					 struct ldb_context *ldb,
					 const struct ldb_val val,
					 const struct es_data *data)
{
	struct aes_gcm_128_context cctx;
	struct EncryptedSecret *es = NULL;
	DATA_BLOB pt = data_blob_null;
	struct ldb_val enc = data_blob_null;
	DATA_BLOB key_blob = data_blob_null;
	int rc;
	TALLOC_CTX *frame = talloc_stackframe();

	es = makeEncryptedSecret(ldb, frame);
	if (es == NULL) {
		goto error_exit;
	}

	pt = makePlainText(frame, ldb, val);
	if (pt.length == 0) {
		goto error_exit;
	}

	/*
	 * Set the encryption key
	 */
	key_blob = get_key(data);
	if (key_blob.length != AES_BLOCK_SIZE) {
		ldb_asprintf_errstring(ldb,
				       "Invalid EncryptedSecrets key size, "
				       "expected %u bytes and is %zu bytes\n",
				       AES_BLOCK_SIZE,
				       key_blob.length);
		goto error_exit;
	}

	/*
	 * Set the initialisation vector
	 */
	{
		uint8_t *iv = talloc_zero_size(frame, AES_GCM_128_IV_SIZE);
		if (iv == NULL) {
			ldb_set_errstring(ldb,
					  "Out of memory allocating iv\n");
			goto error_exit;
		}

		generate_random_buffer(iv, AES_GCM_128_IV_SIZE);

		es->iv.length = AES_GCM_128_IV_SIZE;
		es->iv.data   = iv;
	}

	/*
	 * Encrypt the value, and append the GCM digest to the encrypted
	 * data so that it can be decrypted and validated by the
	 * gnutls aead decryption routines.
	 */
	{
		uint8_t *ct = talloc_zero_size(frame, pt.length + AES_BLOCK_SIZE);
		if (ct == NULL) {
			ldb_oom(ldb);
			goto error_exit;
		}

		memcpy(ct, pt.data, pt.length);
		es->encrypted.length = pt.length + AES_BLOCK_SIZE;
		es->encrypted.data   = ct;
	}

	aes_gcm_128_init(&cctx, key_blob.data, es->iv.data);
	aes_gcm_128_updateA(&cctx,
		    (uint8_t *)&es->header,
		    sizeof(struct EncryptedSecretHeader));
	aes_gcm_128_crypt(&cctx, es->encrypted.data, pt.length);
	aes_gcm_128_updateC(&cctx, es->encrypted.data, pt.length);
	aes_gcm_128_digest(&cctx, &es->encrypted.data[pt.length]);

	rc = ndr_push_struct_blob(&enc,
				  ctx,
				  es,
				  (ndr_push_flags_fn_t)
					ndr_push_EncryptedSecret);
	if (!NDR_ERR_CODE_IS_SUCCESS(rc)) {
		ldb_set_errstring(ldb,
				  "Unable to ndr push EncryptedSecret\n");
		goto error_exit;
	}
	TALLOC_FREE(frame);
	return enc;

error_exit:
	*err = LDB_ERR_OPERATIONS_ERROR;
	TALLOC_FREE(frame);
	return data_blob_null;
}
Esempio n. 26
0
/*
  search for matching records
*/
static int lldb_search(struct lldb_context *lldb_ac)
{
	struct ldb_context *ldb;
	struct lldb_private *lldb = lldb_ac->lldb;
	struct ldb_module *module = lldb_ac->module;
	struct ldb_request *req = lldb_ac->req;
	struct timeval tv;
	int ldap_scope;
	char *search_base;
	char *expression;
	int ret;

	ldb = ldb_module_get_ctx(module);

	if (!req->callback || !req->context) {
		ldb_set_errstring(ldb, "Async interface called with NULL callback function or NULL context");
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (req->op.search.tree == NULL) {
		ldb_set_errstring(ldb, "Invalid expression parse tree");
		return LDB_ERR_OPERATIONS_ERROR;
	}

	if (req->controls != NULL) {
		ldb_debug(ldb, LDB_DEBUG_WARNING, "Controls are not yet supported by ldb_ldap backend!");
	}

	ldb_request_set_state(req, LDB_ASYNC_PENDING);

	search_base = ldb_dn_alloc_linearized(lldb_ac, req->op.search.base);
	if (req->op.search.base == NULL) {
		search_base = talloc_strdup(lldb_ac, "");
	}
	if (search_base == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	expression = ldb_filter_from_tree(lldb_ac, req->op.search.tree);
	if (expression == NULL) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	switch (req->op.search.scope) {
	case LDB_SCOPE_BASE:
		ldap_scope = LDAP_SCOPE_BASE;
		break;
	case LDB_SCOPE_ONELEVEL:
		ldap_scope = LDAP_SCOPE_ONELEVEL;
		break;
	default:
		ldap_scope = LDAP_SCOPE_SUBTREE;
		break;
	}

	tv.tv_sec = req->timeout;
	tv.tv_usec = 0;

	ret = ldap_search_ext(lldb->ldap, search_base, ldap_scope, 
			      expression, 
			      discard_const_p(char *, req->op.search.attrs),
			      0,
			      NULL,
			      NULL,
			      &tv,
			      LDAP_NO_LIMIT,
			      &lldb_ac->msgid);

	if (ret != LDAP_SUCCESS) {
		ldb_set_errstring(ldb, ldap_err2string(ret));
	}

	return lldb_ldap_to_ldb(ret);
}
Esempio n. 27
0
/* return false if the request is still in progress
 * return true if the request is completed
 */
static bool lldb_parse_result(struct lldb_context *ac, LDAPMessage *result)
{
	struct ldb_context *ldb;
	struct lldb_private *lldb = ac->lldb;
	LDAPControl **serverctrlsp = NULL;
	char **referralsp = NULL;
	char *matcheddnp = NULL;
	char *errmsgp = NULL;
	LDAPMessage *msg;
	int type;
	struct ldb_message *ldbmsg;
	char *referral;
	bool callback_failed;
	bool request_done;
	bool lret;
	unsigned int i;
	int ret;

	ldb = ldb_module_get_ctx(ac->module);

	type = ldap_msgtype(result);
	callback_failed = false;
	request_done = false;

	switch (type) {
	case LDAP_RES_SEARCH_ENTRY:

		msg = ldap_first_entry(lldb->ldap, result);
	       	if (msg != NULL) {
			BerElement *berptr = NULL;
			char *attr, *dn;

			ldbmsg = ldb_msg_new(ac);
			if (!ldbmsg) {
				ldb_oom(ldb);
				ret = LDB_ERR_OPERATIONS_ERROR;
				break;
			}

			dn = ldap_get_dn(lldb->ldap, msg);
			if (!dn) {
				ldb_oom(ldb);
				talloc_free(ldbmsg);
				ret = LDB_ERR_OPERATIONS_ERROR;
				break;
			}
			ldbmsg->dn = ldb_dn_new(ldbmsg, ldb, dn);
			if ( ! ldb_dn_validate(ldbmsg->dn)) {
				ldb_asprintf_errstring(ldb, "Invalid DN '%s' in reply", dn);
				talloc_free(ldbmsg);
				ret = LDB_ERR_OPERATIONS_ERROR;
				ldap_memfree(dn);
				break;
			}
			ldap_memfree(dn);

			ldbmsg->num_elements = 0;
			ldbmsg->elements = NULL;

			/* loop over all attributes */
			for (attr=ldap_first_attribute(lldb->ldap, msg, &berptr);
			     attr;
			     attr=ldap_next_attribute(lldb->ldap, msg, berptr)) {
				struct berval **bval;
				bval = ldap_get_values_len(lldb->ldap, msg, attr);

				if (bval) {
					lldb_add_msg_attr(ldb, ldbmsg, attr, bval);
					ldap_value_free_len(bval);
				}
			}
			if (berptr) ber_free(berptr, 0);

			ret = ldb_module_send_entry(ac->req, ldbmsg, NULL /* controls not yet supported */);
			if (ret != LDB_SUCCESS) {
				ldb_asprintf_errstring(ldb, "entry send failed: %s",
						       ldb_errstring(ldb));
				callback_failed = true;
			}
		} else {
			ret = LDB_ERR_OPERATIONS_ERROR;
		}
		break;

	case LDAP_RES_SEARCH_REFERENCE:

		ret = ldap_parse_reference(lldb->ldap, result,
					   &referralsp, &serverctrlsp, 0);
		if (ret != LDAP_SUCCESS) {
			ldb_asprintf_errstring(ldb, "ldap reference parse error: %s : %s",
					       ldap_err2string(ret), errmsgp);
			ret = LDB_ERR_OPERATIONS_ERROR;
			break;
		}
		if (referralsp == NULL) {
			ldb_asprintf_errstring(ldb, "empty ldap referrals list");
			ret = LDB_ERR_PROTOCOL_ERROR;
			break;
		}

		for (i = 0; referralsp[i]; i++) {
			referral = talloc_strdup(ac, referralsp[i]);

			ret = ldb_module_send_referral(ac->req, referral);
			if (ret != LDB_SUCCESS) {
				ldb_asprintf_errstring(ldb, "referral send failed: %s",
						       ldb_errstring(ldb));
				callback_failed = true;
				break;
			}
		}
		break;

	case LDAP_RES_SEARCH_RESULT:
	case LDAP_RES_MODIFY:
	case LDAP_RES_ADD:
	case LDAP_RES_DELETE:
	case LDAP_RES_MODDN:

		if (ldap_parse_result(lldb->ldap, result, &ret,
					&matcheddnp, &errmsgp,
					&referralsp, &serverctrlsp, 0) != LDAP_SUCCESS) {
			ret = LDB_ERR_OPERATIONS_ERROR;
		}
		if (ret != LDB_SUCCESS) {
			ldb_asprintf_errstring(ldb, "ldap parse error for type %d: %s : %s",
					       type, ldap_err2string(ret), errmsgp);
			break;
		}

		if (serverctrlsp != NULL) {
			/* FIXME: transform the LDAPControl list into an ldb_control one */
			ac->controls = NULL;
		}

		request_done = true;
		break;

	default:
		ldb_asprintf_errstring(ldb, "unknown ldap return type: %d", type);
		ret = LDB_ERR_PROTOCOL_ERROR;
		break;
	}

	if (ret != LDB_SUCCESS) {

		/* if the callback failed the caller will have freed the
		 * request. Just return and don't try to use it */
		if (callback_failed) {

			/* tell lldb_wait to remove the request from the
			 *  queue */
			lret = true;
			goto free_and_return;
		}

		request_done = true;
	}

	if (request_done) {
		lldb_request_done(ac, ac->controls, ret);
		lret = true;
		goto free_and_return;
	}

	lret = false;

free_and_return:

	if (matcheddnp) ldap_memfree(matcheddnp);
	if (errmsgp && *errmsgp) {
		ldb_set_errstring(ldb, errmsgp);
	}
	if (errmsgp) {
		ldap_memfree(errmsgp);
	}
	if (referralsp) ldap_value_free(referralsp);
	if (serverctrlsp) ldap_controls_free(serverctrlsp);

	ldap_msgfree(result);

	return lret;
}
Esempio n. 28
0
static int lldb_handle_request(struct ldb_module *module, struct ldb_request *req)
{
	struct ldb_context *ldb;
	struct lldb_private *lldb;
	struct lldb_context *ac;
	struct tevent_context *ev;
	struct tevent_timer *te;
	struct timeval tv;
	int ret;

	lldb = talloc_get_type(ldb_module_get_private(module), struct lldb_private);
	ldb = ldb_module_get_ctx(module);

	if (req->starttime == 0 || req->timeout == 0) {
		ldb_set_errstring(ldb, "Invalid timeout settings");
		return LDB_ERR_TIME_LIMIT_EXCEEDED;
	}

	ev = ldb_get_event_context(ldb);
	if (NULL == ev) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ac = talloc_zero(ldb, struct lldb_context);
	if (ac == NULL) {
		ldb_set_errstring(ldb, "Out of Memory");
		return LDB_ERR_OPERATIONS_ERROR;
	}

	ac->module = module;
	ac->req = req;
	ac->lldb = lldb;
	ac->msgid = 0;

	if (lldb_dn_is_special(req)) {
		tv.tv_sec = 0;
		tv.tv_usec = 0;
		te = tevent_add_timer(ev, ac, tv,
				     lldb_auto_done_callback, ac);
		if (NULL == te) {
			return LDB_ERR_OPERATIONS_ERROR;
		}

		return LDB_SUCCESS;
	}

	switch (ac->req->operation) {
	case LDB_SEARCH:
		ret = lldb_search(ac);
		break;
	case LDB_ADD:
		ret = lldb_add(ac);
		break;
	case LDB_MODIFY:
		ret = lldb_modify(ac);
		break;
	case LDB_DELETE:
		ret = lldb_delete(ac);
		break;
	case LDB_RENAME:
		ret = lldb_rename(ac);
		break;
	default:
		/* no other op supported */
		ret = LDB_ERR_PROTOCOL_ERROR;
		break;
	}

	if (ret != LDB_SUCCESS) {
		lldb_request_done(ac, NULL, ret);
		return ret;
	}

	tv.tv_sec = 0;
	tv.tv_usec = 0;
	te = tevent_add_timer(ev, ac, tv, lldb_callback, ac);
	if (NULL == te) {
		return LDB_ERR_OPERATIONS_ERROR;
	}


	tv.tv_sec = req->starttime + req->timeout;
	tv.tv_usec = 0;
	te = tevent_add_timer(ev, ac, tv, lldb_timeout, ac);
	if (NULL == te) {
		return LDB_ERR_OPERATIONS_ERROR;
	}

	return LDB_SUCCESS;
}
Esempio n. 29
0
/* Store the DN of a single search result in context. */
static int map_search_self_callback(struct ldb_request *req, struct ldb_reply *ares)
{
	struct ldb_context *ldb;
	struct map_context *ac;
	int ret;

	ac = talloc_get_type(req->context, struct map_context);
	ldb = ldb_module_get_ctx(ac->module);

	if (!ares) {
		return ldb_module_done(ac->req, NULL, NULL,
					LDB_ERR_OPERATIONS_ERROR);
	}
	if (ares->error != LDB_SUCCESS) {
		return ldb_module_done(ac->req, ares->controls,
					ares->response, ares->error);
	}

	/* We are interested only in the single reply */
	switch(ares->type) {
	case LDB_REPLY_ENTRY:
		/* We have already found a remote DN */
		if (ac->local_dn) {
			ldb_set_errstring(ldb,
					  "Too many results!");
			return ldb_module_done(ac->req, NULL, NULL,
						LDB_ERR_OPERATIONS_ERROR);
		}

		/* Store local DN */
		ac->local_dn = talloc_steal(ac, ares->message->dn);
		break;

	case LDB_REPLY_DONE:

		switch (ac->req->operation) {
		case LDB_MODIFY:
			ret = map_modify_do_local(ac);
			break;
		case LDB_DELETE:
			ret = map_delete_do_local(ac);
			break;
		case LDB_RENAME:
			ret = map_rename_do_local(ac);
			break;
		default:
			/* if we get here we have definitely a problem */
			ret = LDB_ERR_OPERATIONS_ERROR;
		}
		if (ret != LDB_SUCCESS) {
			return ldb_module_done(ac->req, NULL, NULL,
						LDB_ERR_OPERATIONS_ERROR);
		}

	default:
		/* ignore referrals */
		break;
	}

	talloc_free(ares);
	return LDB_SUCCESS;
}