summaryrefslogtreecommitdiffstats
path: root/daemons
diff options
context:
space:
mode:
authorSimo Sorce <ssorce@redhat.com>2011-06-01 17:58:21 -0400
committerSimo Sorce <ssorce@redhat.com>2011-08-26 08:24:49 -0400
commite9e426354f28ca01586b1b5ef7130b19b392232b (patch)
treeed72384563ab5b83d862a0e8b57d01bee4432486 /daemons
parentd25370a57961cebaa75983bedca37b3fdf5094a2 (diff)
downloadfreeipa-e9e426354f28ca01586b1b5ef7130b19b392232b.tar.gz
freeipa-e9e426354f28ca01586b1b5ef7130b19b392232b.tar.xz
freeipa-e9e426354f28ca01586b1b5ef7130b19b392232b.zip
ipa-kdb: add functions to change principals
Diffstat (limited to 'daemons')
-rw-r--r--daemons/ipa-kdb/Makefile.am5
-rw-r--r--daemons/ipa-kdb/ipa_kdb.h36
-rw-r--r--daemons/ipa-kdb/ipa_kdb_principals.c764
3 files changed, 804 insertions, 1 deletions
diff --git a/daemons/ipa-kdb/Makefile.am b/daemons/ipa-kdb/Makefile.am
index 2b97a93d..a632bb01 100644
--- a/daemons/ipa-kdb/Makefile.am
+++ b/daemons/ipa-kdb/Makefile.am
@@ -1,8 +1,12 @@
NULL =
+KRB5_UTIL_DIR = ../../util
+KRB5_UTIL_SRCS = $(KRB5_UTIL_DIR)/ipa_krb5.c
+
INCLUDES = \
-I. \
-I$(srcdir) \
+ -I$(KRB5_UTIL_DIR) \
-DPREFIX=\""$(prefix)"\" \
-DBINDIR=\""$(bindir)"\" \
-DLIBDIR=\""$(libdir)"\" \
@@ -25,6 +29,7 @@ ipadb_la_SOURCES = \
ipa_kdb.c \
ipa_kdb_common.c \
ipa_kdb_principals.c \
+ $(KRB5_UTIL_SRCS) \
$(NULL)
ipadb_la_LDFLAGS = \
diff --git a/daemons/ipa-kdb/ipa_kdb.h b/daemons/ipa-kdb/ipa_kdb.h
index 7e20f98a..26c6a3df 100644
--- a/daemons/ipa-kdb/ipa_kdb.h
+++ b/daemons/ipa-kdb/ipa_kdb.h
@@ -24,6 +24,12 @@
#define _GNU_SOURCE 1
#endif
+/* although we have nothing to do with SECURID yet, there are a
+ * couple of TL_DATA Ids that need it to be available.
+ * We need them to be avilable even if SECURID is not used for
+ * filtering purposes */
+#define SECURID 1
+
#include <errno.h>
#include <kdb.h>
#include <ldap.h>
@@ -34,6 +40,36 @@
#include <arpa/inet.h>
#include <endian.h>
+#include "ipa_krb5.h"
+
+/* easier to copy the defines here than to mess with kadm5/admin.h
+ * for now */
+#define KMASK_PRINCIPAL 0x000001
+#define KMASK_PRINC_EXPIRE_TIME 0x000002
+#define KMASK_PW_EXPIRATION 0x000004
+#define KMASK_LAST_PWD_CHANGE 0x000008
+#define KMASK_ATTRIBUTES 0x000010
+#define KMASK_MAX_LIFE 0x000020
+#define KMASK_MOD_TIME 0x000040
+#define KMASK_MOD_NAME 0x000080
+#define KMASK_KVNO 0x000100
+#define KMASK_MKVNO 0x000200
+#define KMASK_AUX_ATTRIBUTES 0x000400
+#define KMASK_POLICY 0x000800
+#define KMASK_POLICY_CLR 0x001000
+/* version 2 masks */
+#define KMASK_MAX_RLIFE 0x002000
+#define KMASK_LAST_SUCCESS 0x004000
+#define KMASK_LAST_FAILED 0x008000
+#define KMASK_FAIL_AUTH_COUNT 0x010000
+#define KMASK_KEY_DATA 0x020000
+#define KMASK_TL_DATA 0x040000
+#define KMASK_LOAD 0x200000
+
+/* MIT Kerberos sanctioned hack to carry private data around.
+ * In krb5 1.10 this should be superceeded by a better mechanism */
+#define KDB_TL_USER_INFO 0x7ffe
+
struct ipadb_context {
char *uri;
char *base;
diff --git a/daemons/ipa-kdb/ipa_kdb_principals.c b/daemons/ipa-kdb/ipa_kdb_principals.c
index d6a816f9..bd84f5b3 100644
--- a/daemons/ipa-kdb/ipa_kdb_principals.c
+++ b/daemons/ipa-kdb/ipa_kdb_principals.c
@@ -66,6 +66,16 @@ static char *std_tktpolicy_attrs[] = {
#define MAXTKTLIFE_BIT 0x02
#define MAXRENEWABLEAGE_BIT 0x04
+static char *std_principal_obj_classes[] = {
+ "krbprincipal",
+ "krbprincipalaux",
+ "krbTicketPolicyAux",
+
+ NULL
+};
+
+#define STD_PRINCIPAL_OBJ_CLASSES_SIZE (sizeof(std_principal_obj_classes) / sizeof(char *) - 1)
+
static int ipadb_ldap_attr_to_tl_data(LDAP *lcontext, LDAPMessage *le,
char *attrname,
krb5_tl_data **result, int *num)
@@ -855,11 +865,763 @@ void ipadb_free_principal(krb5_context kcontext, krb5_db_entry *entry)
}
}
+static krb5_error_code ipadb_get_tl_data(krb5_db_entry *entry,
+ krb5_int16 type,
+ krb5_ui_2 length,
+ krb5_octet *data)
+{
+ krb5_tl_data *td;
+
+ for (td = entry->tl_data; td; td = td->tl_data_next) {
+ if (td->tl_data_type == type) {
+ break;
+ }
+ }
+ if (!td) {
+ return ENOENT;
+ }
+
+ if (td->tl_data_length != length) {
+ return EINVAL;
+ }
+
+ memcpy(data, td->tl_data_contents, length);
+
+ return 0;
+}
+
+struct ipadb_mods {
+ LDAPMod **mods;
+ int alloc_size;
+ int tip;
+};
+
+static int new_ipadb_mods(struct ipadb_mods **imods)
+{
+ struct ipadb_mods *r;
+
+ r = malloc(sizeof(struct ipadb_mods));
+ if (!r) {
+ return ENOMEM;
+ }
+
+ /* alloc the average space for a full change of all ldap attrinbutes */
+ r->alloc_size = 15;
+ r->mods = calloc(r->alloc_size, sizeof(LDAPMod *));
+ if (!r->mods) {
+ free(r);
+ return ENOMEM;
+ }
+ r->tip = 0;
+
+ *imods = r;
+ return 0;
+}
+
+static void ipadb_mods_free(struct ipadb_mods *imods)
+{
+ if (imods == NULL) {
+ return;
+ }
+
+ ldap_mods_free(imods->mods, 1);
+ free(imods);
+}
+
+static krb5_error_code ipadb_mods_new(struct ipadb_mods *imods,
+ LDAPMod **slot)
+{
+ LDAPMod **lmods = NULL;
+ LDAPMod *m;
+ int n;
+
+ lmods = imods->mods;
+ for (n = imods->tip; n < imods->alloc_size && lmods[n] != NULL; n++) {
+ /* find empty slot */ ;
+ }
+
+ if (n + 1 > imods->alloc_size) {
+ /* need to increase size */
+ lmods = realloc(imods->mods, (n * 2) * sizeof(LDAPMod *));
+ if (!lmods) {
+ return ENOMEM;
+ }
+ imods->mods = lmods;
+ imods->alloc_size = n * 2;
+ memset(&lmods[n + 1], 0,
+ (imods->alloc_size - n - 1) * sizeof(LDAPMod *));
+ }
+
+ m = calloc(1, sizeof(LDAPMod));
+ if (!m) {
+ return ENOMEM;
+ }
+ imods->tip = n;
+ *slot = imods->mods[n] = m;
+ return 0;
+}
+
+static void ipadb_mods_free_tip(struct ipadb_mods *imods)
+{
+ LDAPMod *m;
+ int i;
+
+ if (imods->alloc_size == 0) {
+ return;
+ }
+
+ m = imods->mods[imods->tip];
+
+ if (!m) {
+ return;
+ }
+
+ free(m->mod_type);
+ if (m->mod_values) {
+ for (i = 0; m->mod_values[i]; i++) {
+ free(m->mod_values[i]);
+ }
+ }
+ free(m->mod_values);
+ free(m);
+
+ imods->mods[imods->tip] = NULL;
+ imods->tip--;
+}
+
+static krb5_error_code ipadb_get_ldap_mod_str(struct ipadb_mods *imods,
+ char *attribute, char *value,
+ int mod_op)
+{
+ krb5_error_code kerr;
+ LDAPMod *m = NULL;
+
+ kerr = ipadb_mods_new(imods, &m);
+ if (kerr) {
+ return kerr;
+ }
+
+ m->mod_op = mod_op;
+ m->mod_type = strdup(attribute);
+ if (!m->mod_type) {
+ kerr = ENOMEM;
+ goto done;
+ }
+ m->mod_values = calloc(2, sizeof(char *));
+ if (!m->mod_values) {
+ kerr = ENOMEM;
+ goto done;
+ }
+ m->mod_values[0] = strdup(value);
+ if (!m->mod_values[0]) {
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ kerr = 0;
+
+done:
+ if (kerr) {
+ ipadb_mods_free_tip(imods);
+ }
+ return kerr;
+}
+
+static krb5_error_code ipadb_get_ldap_mod_int(struct ipadb_mods *imods,
+ char *attribute, int value,
+ int mod_op)
+{
+ krb5_error_code kerr;
+ char *v = NULL;
+ int ret;
+
+ ret = asprintf(&v, "%d", value);
+ if (ret == -1) {
+ kerr = KRB5_KDB_INTERNAL_ERROR;
+ goto done;
+ }
+
+ kerr = ipadb_get_ldap_mod_str(imods, attribute, v, mod_op);
+
+done:
+ free(v);
+ return kerr;
+}
+
+static krb5_error_code ipadb_get_ldap_mod_time(struct ipadb_mods *imods,
+ char *attribute,
+ krb5_timestamp value,
+ int mod_op)
+{
+ struct tm date, *t;
+ time_t timeval;
+ char v[20];
+
+ timeval = (time_t)value;
+ t = gmtime_r(&timeval, &date);
+ if (t == NULL) {
+ return EINVAL;
+ }
+
+ strftime(v, 20, "%Y%m%d%H%M%SZ", &date);
+
+ return ipadb_get_ldap_mod_str(imods, attribute, v, mod_op);
+}
+
+static krb5_error_code ipadb_get_ldap_mod_bvalues(struct ipadb_mods *imods,
+ char *attribute,
+ struct berval **values,
+ int num_values,
+ int mod_op)
+{
+ krb5_error_code kerr;
+ LDAPMod *m = NULL;
+ int i;
+
+ if (values == NULL || values[0] == NULL || num_values <= 0) {
+ return EINVAL;
+ }
+
+ kerr = ipadb_mods_new(imods, &m);
+ if (kerr) {
+ return kerr;
+ }
+
+ m->mod_op = mod_op | LDAP_MOD_BVALUES;
+ m->mod_type = strdup(attribute);
+ if (!m->mod_type) {
+ kerr = ENOMEM;
+ goto done;
+ }
+ m->mod_bvalues = calloc(num_values + 1, sizeof(struct berval *));
+ if (!m->mod_bvalues) {
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0; i < num_values; i++) {
+ m->mod_bvalues[i] = values[i];
+ }
+
+ kerr = 0;
+
+done:
+ if (kerr) {
+ /* we need to free bvalues manually here otherwise
+ * ipadb_mods_free_tip will free contents which we
+ * did not allocate here */
+ free(m->mod_bvalues);
+ m->mod_bvalues = NULL;
+ ipadb_mods_free_tip(imods);
+ }
+ return kerr;
+}
+
+static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods,
+ krb5_tl_data *tl_data,
+ int mod_op)
+{
+ krb5_error_code kerr;
+ krb5_tl_data *data;
+ struct berval **bvs = NULL;
+ krb5_int16 be_type;
+ int n, i;
+
+ for (n = 0, data = tl_data; data; data = data->tl_data_next) {
+ if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE ||
+ data->tl_data_type == KRB5_TL_KADM_DATA ||
+ data->tl_data_type == KRB5_TL_DB_ARGS ||
+ data->tl_data_type == KRB5_TL_MKVNO ||
+ data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK ||
+ data->tl_data_type == KDB_TL_USER_INFO) {
+ continue;
+ }
+ n++;
+ }
+
+ if (n == 0) {
+ return ENOENT;
+ }
+
+ bvs = calloc(n + 1, sizeof(struct berval *));
+ if (!bvs) {
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ for (i = 0, data = tl_data; data; data = data->tl_data_next) {
+
+ if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE ||
+ data->tl_data_type == KRB5_TL_KADM_DATA ||
+ data->tl_data_type == KRB5_TL_DB_ARGS ||
+ data->tl_data_type == KRB5_TL_MKVNO ||
+ data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK ||
+ data->tl_data_type == KDB_TL_USER_INFO) {
+ continue;
+ }
+
+ be_type = htons(data->tl_data_type);
+
+ bvs[i] = calloc(1, sizeof(struct berval));
+ if (!bvs[i]) {
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ bvs[i]->bv_len = data->tl_data_length + 2;
+ bvs[i]->bv_val = malloc(bvs[i]->bv_len);
+ if (!bvs[i]->bv_val) {
+ kerr = ENOMEM;
+ goto done;
+ }
+ memcpy(bvs[i]->bv_val, &be_type, 2);
+ memcpy(&(bvs[i]->bv_val[2]), data->tl_data_contents, data->tl_data_length);
+
+ i++;
+
+ if (i > n) {
+ kerr = KRB5_KDB_INTERNAL_ERROR;
+ goto done;
+ }
+ }
+
+ kerr = ipadb_get_ldap_mod_bvalues(imods, "krbExtraData", bvs, i, mod_op);
+
+done:
+ if (kerr) {
+ for (i = 0; bvs && bvs[i]; i++) {
+ free(bvs[i]->bv_val);
+ free(bvs[i]);
+ }
+ }
+ free(bvs);
+ return kerr;
+}
+
+static krb5_error_code ipadb_get_mkvno_from_tl_data(krb5_tl_data *tl_data,
+ int *mkvno)
+{
+ krb5_tl_data *data;
+ int master_kvno = 0;
+ krb5_int16 tmp;
+
+ for (data = tl_data; data; data = data->tl_data_next) {
+
+ if (data->tl_data_type != KRB5_TL_MKVNO) {
+ continue;
+ }
+
+ if (data->tl_data_length != 2) {
+ return KRB5_KDB_TRUNCATED_RECORD;
+ }
+
+ memcpy(&tmp, data->tl_data_contents, 2);
+ master_kvno = le16toh(tmp);
+
+ break;
+ }
+
+ if (master_kvno == 0) {
+ /* fall back to std mkvno of 1 */
+ *mkvno = 1;
+ } else {
+ *mkvno = master_kvno;
+ }
+
+ return 0;
+}
+
+static krb5_error_code ipadb_get_ldap_mod_key_data(struct ipadb_mods *imods,
+ krb5_key_data *key_data,
+ int n_key_data, int mkvno,
+ int mod_op)
+{
+ krb5_error_code kerr;
+ struct berval *bval = NULL;
+ int ret;
+
+ ret = ber_encode_krb5_key_data(key_data, n_key_data, mkvno, &bval);
+ if (ret != 0) {
+ kerr = ret;
+ goto done;
+ }
+
+ kerr = ipadb_get_ldap_mod_bvalues(imods, "krbPrincipalKey",
+ &bval, 1, mod_op);
+
+done:
+ if (kerr) {
+ ber_bvfree(bval);
+ }
+ return kerr;
+}
+
+static krb5_error_code ipadb_entry_to_mods(struct ipadb_mods *imods,
+ krb5_db_entry *entry,
+ char *principal,
+ int mod_op)
+{
+ krb5_error_code kerr;
+ krb5_int32 time32le;
+ int mkvno;
+
+ /* check each mask flag in order */
+
+ /* KADM5_PRINCIPAL */
+ if (entry->mask & KMASK_PRINCIPAL) {
+ kerr = ipadb_get_ldap_mod_str(imods, "krbPrincipalName",
+ principal, mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_PRINC_EXPIRE_TIME */
+ if (entry->mask & KMASK_PRINC_EXPIRE_TIME) {
+ kerr = ipadb_get_ldap_mod_time(imods,
+ "krbPrincipalExpiration",
+ entry->expiration,
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_PW_EXPIRATION */
+ if (entry->mask & KMASK_PW_EXPIRATION) {
+ kerr = ipadb_get_ldap_mod_time(imods,
+ "krbPasswordExpiration",
+ entry->pw_expiration,
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_LAST_PWD_CHANGE */
+ /* apparently, at least some versions of kadmin fail to set this flag
+ * when they do include a pwd change timestamp in TL_DATA.
+ * So for now always check for it regardless. */
+#if KADM5_ACTUALLY_SETS_LAST_PWD_CHANGE
+ if (entry->mask & KMASK_LAST_PWD_CHANGE) {
+ if (!entry->n_tl_data) {
+ kerr = EINVAL;
+ goto done;
+ }
+
+#else
+ if (entry->n_tl_data) {
+#endif
+ kerr = ipadb_get_tl_data(entry,
+ KRB5_TL_LAST_PWD_CHANGE,
+ sizeof(time32le),
+ (krb5_octet *)&time32le);
+ if (kerr && kerr != ENOENT) {
+ goto done;
+ }
+ if (kerr == 0) {
+ kerr = ipadb_get_ldap_mod_time(imods,
+ "krbLastPwdChange",
+ le32toh(time32le),
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+ }
+
+ /* KADM5_ATTRIBUTES */
+ if (entry->mask & KMASK_ATTRIBUTES) {
+ kerr = ipadb_get_ldap_mod_int(imods,
+ "krbTicketFlags",
+ (int)entry->attributes,
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_MAX_LIFE */
+ if (entry->mask & KMASK_MAX_LIFE) {
+ kerr = ipadb_get_ldap_mod_int(imods,
+ "krbMaxTicketLife",
+ (int)entry->max_life,
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_MOD_TIME */
+ /* KADM5_MOD_NAME */
+ /* KADM5_KVNO */
+ /* KADM5_MKVNO */
+ /* KADM5_AUX_ATTRIBUTES */
+ /* KADM5_POLICY */
+ /* KADM5_POLICY_CLR */
+
+ /* version 2 masks */
+ /* KADM5_MAX_RLIFE */
+ if (entry->mask & KMASK_MAX_RLIFE) {
+ kerr = ipadb_get_ldap_mod_int(imods,
+ "krbMaxRenewableAge",
+ (int)entry->max_renewable_life,
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_LAST_SUCCESS */
+ if (entry->mask & KMASK_LAST_SUCCESS) {
+ kerr = ipadb_get_ldap_mod_time(imods,
+ "krbLastSuccessfulAuth",
+ entry->last_success,
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_LAST_FAILED */
+ if (entry->mask & KMASK_LAST_FAILED) {
+ kerr = ipadb_get_ldap_mod_time(imods,
+ "krbLastFailedAuth",
+ entry->last_failed,
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_FAIL_AUTH_COUNT */
+ if (entry->mask & KMASK_FAIL_AUTH_COUNT) {
+ kerr = ipadb_get_ldap_mod_int(imods,
+ "krbLoginFailedCount",
+ (int)entry->fail_auth_count,
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_KEY_DATA */
+ if (entry->mask & KMASK_KEY_DATA) {
+ /* TODO: password changes should go via change_pwd
+ * then we can get clear text and set all needed
+ * LDAP attributes */
+
+ kerr = ipadb_get_mkvno_from_tl_data(entry->tl_data, &mkvno);
+ if (kerr) {
+ goto done;
+ }
+
+ kerr = ipadb_get_ldap_mod_key_data(imods,
+ entry->key_data,
+ entry->n_key_data,
+ mkvno,
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ /* KADM5_TL_DATA */
+ if (entry->mask & KMASK_TL_DATA) {
+ kerr = ipadb_get_tl_data(entry,
+ KRB5_TL_LAST_ADMIN_UNLOCK,
+ sizeof(time32le),
+ (krb5_octet *)&time32le);
+ if (kerr && kerr != ENOENT) {
+ goto done;
+ }
+ if (kerr == 0) {
+ kerr = ipadb_get_ldap_mod_time(imods,
+ "krbLastAdminUnlock",
+ le32toh(time32le),
+ mod_op);
+ if (kerr) {
+ goto done;
+ }
+ }
+
+ kerr = ipadb_get_ldap_mod_extra_data(imods,
+ entry->tl_data,
+ mod_op);
+ if (kerr && kerr != ENOENT) {
+ goto done;
+ }
+ }
+
+ /* KADM5_LOAD */
+
+ kerr = 0;
+
+done:
+ return kerr;
+}
+
+/* adds default objectclasses and attributes */
+static krb5_error_code ipadb_entry_default_attrs(struct ipadb_mods *imods)
+{
+ krb5_error_code kerr;
+ LDAPMod *m = NULL;
+ int i;
+
+ kerr = ipadb_mods_new(imods, &m);
+ if (kerr) {
+ return kerr;
+ }
+
+ m->mod_op = LDAP_MOD_ADD;
+ m->mod_type = strdup("objectClass");
+ if (!m->mod_type) {
+ kerr = ENOMEM;
+ goto done;
+ }
+ m->mod_values = calloc(STD_PRINCIPAL_OBJ_CLASSES_SIZE + 1, sizeof(char *));
+ if (!m->mod_values) {
+ kerr = ENOMEM;
+ goto done;
+ }
+ for (i = 0; i < STD_PRINCIPAL_OBJ_CLASSES_SIZE; i++) {
+ m->mod_values[i] = strdup(std_principal_obj_classes[i]);
+ if (!m->mod_values[i]) {
+ kerr = ENOMEM;
+ goto done;
+ }
+ }
+
+ kerr = 0;
+
+done:
+ if (kerr) {
+ ipadb_mods_free_tip(imods);
+ }
+ return kerr;
+}
+
+static krb5_error_code ipadb_add_principal(krb5_context kcontext,
+ krb5_db_entry *entry)
+{
+ struct ipadb_context *ipactx;
+ krb5_error_code kerr;
+ char *principal = NULL;
+ struct ipadb_mods *imods = NULL;
+ char *dn = NULL;
+ int ret;
+
+ ipactx = ipadb_get_context(kcontext);
+ if (!ipactx) {
+ kerr = KRB5_KDB_DBNOTINITED;
+ goto done;
+ }
+
+ kerr = krb5_unparse_name(kcontext, entry->princ, &principal);
+ if (kerr != 0) {
+ goto done;
+ }
+
+ ret = asprintf(&dn, "krbPrincipalName=%s,cn=%s,cn=kerberos,%s",
+ principal, ipactx->realm, ipactx->base);
+ if (ret == -1) {
+ kerr = ENOMEM;
+ goto done;
+ }
+
+ ret = new_ipadb_mods(&imods);
+ if (ret != 0) {
+ kerr = ret;
+ goto done;
+ }
+
+ kerr = ipadb_entry_to_mods(imods, entry, principal, LDAP_MOD_ADD);
+ if (kerr != 0) {
+ goto done;
+ }
+
+ kerr = ipadb_entry_default_attrs(imods);
+ if (kerr != 0) {
+ goto done;
+ }
+
+ kerr = ipadb_simple_add(ipactx, dn, imods->mods);
+
+done:
+ ipadb_mods_free(imods);
+ krb5_free_unparsed_name(kcontext, principal);
+ ldap_memfree(dn);
+ return kerr;
+}
+
+static krb5_error_code ipadb_modify_principal(krb5_context kcontext,
+ krb5_db_entry *entry)
+{
+ struct ipadb_context *ipactx;
+ krb5_error_code kerr;
+ char *principal = NULL;
+ LDAPMessage *res = NULL;
+ LDAPMessage *lentry;
+ struct ipadb_mods *imods = NULL;
+ char *dn = NULL;
+
+ ipactx = ipadb_get_context(kcontext);
+ if (!ipactx) {
+ return KRB5_KDB_DBNOTINITED;
+ }
+
+ kerr = krb5_unparse_name(kcontext, entry->princ, &principal);
+ if (kerr != 0) {
+ goto done;
+ }
+
+ kerr = ipadb_fetch_principals(ipactx, principal, &res);
+ if (kerr != 0) {
+ goto done;
+ }
+
+ /* FIXME: no alias allowed for now, should we allow modifies
+ * by alias name ? */
+ kerr = ipadb_find_principal(kcontext, 0, res, &principal, &lentry);
+ if (kerr != 0) {
+ goto done;
+ }
+
+ dn = ldap_get_dn(ipactx->lcontext, lentry);
+ if (!dn) {
+ kerr = KRB5_KDB_INTERNAL_ERROR;
+ goto done;
+ }
+
+ kerr = new_ipadb_mods(&imods);
+ if (kerr) {
+ goto done;
+ }
+
+ kerr = ipadb_entry_to_mods(imods, entry, principal, LDAP_MOD_REPLACE);
+ if (kerr != 0) {
+ goto done;
+ }
+
+ kerr = ipadb_simple_modify(ipactx, dn, imods->mods);
+
+done:
+ ipadb_mods_free(imods);
+ ldap_msgfree(res);
+ krb5_free_unparsed_name(kcontext, principal);
+ ldap_memfree(dn);
+ return kerr;
+}
+
krb5_error_code ipadb_put_principal(krb5_context kcontext,
krb5_db_entry *entry,
char **db_args)
{
- return KRB5_PLUGIN_OP_NOTSUPP;
+ if (entry->mask & KMASK_PRINCIPAL) {
+ return ipadb_add_principal(kcontext, entry);
+ } else {
+ return ipadb_modify_principal(kcontext, entry);
+ }
}
static krb5_error_code ipadb_delete_entry(krb5_context kcontext,