diff options
Diffstat (limited to 'src/db/sysdb.c')
-rw-r--r-- | src/db/sysdb.c | 163 |
1 files changed, 150 insertions, 13 deletions
diff --git a/src/db/sysdb.c b/src/db/sysdb.c index 8806fe05f..dd70d5c74 100644 --- a/src/db/sysdb.c +++ b/src/db/sysdb.c @@ -165,33 +165,68 @@ struct ldb_dn *sysdb_netgroup_base_dn(struct sysdb_ctx *ctx, void *memctx, return ldb_dn_new_fmt(memctx, ctx->ldb, SYSDB_TMPL_NETGROUP_BASE, domain); } -errno_t sysdb_group_dn_name(struct sysdb_ctx *ctx, void *memctx, - const char *_dn, char **_name) +errno_t sysdb_get_rdn(struct sysdb_ctx *ctx, void *memctx, + const char *_dn, char **_name, char **_val) { + errno_t ret; struct ldb_dn *dn; + const char *attr_name = NULL; const struct ldb_val *val; - *_name = NULL; + TALLOC_CTX *tmpctx; - dn = ldb_dn_new_fmt(memctx, ctx->ldb, "%s", _dn); - if (dn == NULL) { + /* We have to create a tmpctx here because + * ldb_dn_new_fmt() fails if memctx is NULL + */ + tmpctx = talloc_new(NULL); + if (!tmpctx) { return ENOMEM; } + dn = ldb_dn_new_fmt(tmpctx, ctx->ldb, "%s", _dn); + if (dn == NULL) { + ret = ENOMEM; + goto done; + } + + if (_name) { + attr_name = ldb_dn_get_rdn_name(dn); + if (attr_name == NULL) { + ret = EINVAL; + goto done; + } + + *_name = talloc_strdup(memctx, attr_name); + if (!_name) { + ret = ENOMEM; + goto done; + } + } + val = ldb_dn_get_rdn_val(dn); if (val == NULL) { - talloc_zfree(dn); - return EINVAL; + ret = EINVAL; + talloc_free(*_name); + goto done; } - *_name = talloc_strndup(memctx, (char *) val->data, val->length); - if (!*_name) { - talloc_zfree(dn); - return ENOMEM; + *_val = talloc_strndup(memctx, (char *) val->data, val->length); + if (!*_val) { + ret = ENOMEM; + talloc_free(*_name); + goto done; } - talloc_zfree(dn); + ret = EOK; - return EOK; +done: + talloc_zfree(tmpctx); + return ret; +} + +errno_t sysdb_group_dn_name(struct sysdb_ctx *ctx, void *memctx, + const char *_dn, char **_name) +{ + return sysdb_get_rdn(ctx, memctx, _dn, NULL, _name); } struct ldb_dn *sysdb_domain_dn(struct sysdb_ctx *ctx, void *memctx, @@ -2005,3 +2040,105 @@ done: talloc_free(tmp_ctx); return ret; } + +errno_t sysdb_attrs_primary_name(struct sysdb_ctx *sysdb, + struct sysdb_attrs *attrs, + const char *ldap_attr, + const char **_primary) +{ + errno_t ret; + char *rdn_attr = NULL; + char *rdn_val = NULL; + struct ldb_message_element *sysdb_name_el; + struct ldb_message_element *orig_dn_el; + size_t i; + TALLOC_CTX *tmpctx = NULL; + + tmpctx = talloc_new(NULL); + if (!tmpctx) { + return ENOMEM; + } + + ret = sysdb_attrs_get_el(attrs, + SYSDB_NAME, + &sysdb_name_el); + if (sysdb_name_el->num_values == 0) { + ret = EINVAL; + goto done; + } + + if (sysdb_name_el->num_values == 1) { + /* Entry contains only one name. Just return that */ + *_primary = (const char *)sysdb_name_el->values[0].data; + ret = EOK; + goto done; + } + + /* Multiple values for name. Check whether one matches the RDN */ + + ret = sysdb_attrs_get_el(attrs, SYSDB_ORIG_DN, &orig_dn_el); + if (ret) { + goto done; + } + if (orig_dn_el->num_values == 0) { + DEBUG(7, ("Original DN is not available.\n")); + } else if (orig_dn_el->num_values == 1) { + ret = sysdb_get_rdn(sysdb, tmpctx, + (const char *) orig_dn_el->values[0].data, + &rdn_attr, + &rdn_val); + if (ret != EOK) { + DEBUG(1, ("Could not get rdn from [%s]\n", + (const char *) orig_dn_el->values[0].data)); + goto done; + } + } else { + DEBUG(1, ("Should not have more than one origDN\n")); + ret = EINVAL; + goto done; + } + + /* First check whether the attribute name matches */ + DEBUG(8, ("Comparing attribute names [%s] and [%s]\n", + rdn_attr, ldap_attr)); + if (strcasecmp(rdn_attr, ldap_attr) != 0) { + /* Multiple entries, and the RDN attribute doesn't match. + * We have no way of resolving this deterministically, + * so we'll punt. + */ + DEBUG(1, ("Cannot save entry. It has multiple names and the RDN " + "attribute does not match\n")); + ret = EINVAL; + goto done; + } + + for (i = 0; i < sysdb_name_el->num_values; i++) { + if (strcasecmp(rdn_val, + (const char *)sysdb_name_el->values[i].data) == 0) { + /* This name matches the RDN. Use it */ + break; + } + } + if (i < sysdb_name_el->num_values) { + /* Match was found */ + *_primary = (const char *)sysdb_name_el->values[i].data; + } else { + /* If we can't match the name to the RDN, we just have to + * throw up our hands. There's no deterministic way to + * decide which name is correct. + */ + DEBUG(1, ("Cannot save entry. Unable to determine groupname\n")); + ret = EINVAL; + goto done; + } + + ret = EOK; + +done: + if (ret != EOK) { + DEBUG(1, ("Could not determine primary name: [%d][%s]\n", + ret, strerror(ret))); + } + talloc_free(tmpctx); + return ret; +} |