diff options
Diffstat (limited to 'lib/hdb/hdb-ldap.c')
| -rw-r--r-- | lib/hdb/hdb-ldap.c | 553 |
1 files changed, 335 insertions, 218 deletions
diff --git a/lib/hdb/hdb-ldap.c b/lib/hdb/hdb-ldap.c index c9f3d37cd339..1b4024aa540a 100644 --- a/lib/hdb/hdb-ldap.c +++ b/lib/hdb/hdb-ldap.c @@ -1,7 +1,7 @@ /* * Copyright (c) 1999-2001, 2003, PADL Software Pty Ltd. * Copyright (c) 2004, Andrew Bartlett. - * Copyright (c) 2003 - 2007, Kungliga Tekniska Högskolan. + * Copyright (c) 2003 - 2008, Kungliga Tekniska Högskolan. * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -34,8 +34,6 @@ #include "hdb_locl.h" -RCSID("$Id: hdb-ldap.c 22071 2007-11-14 20:04:50Z lha $"); - #ifdef OPENLDAP #include <lber.h> @@ -48,7 +46,7 @@ static krb5_error_code LDAP_close(krb5_context context, HDB *); static krb5_error_code LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, - hdb_entry_ex * ent); + int flags, hdb_entry_ex * ent); static const char *default_structural_object = "account"; static char *structural_object; @@ -74,7 +72,7 @@ struct hdbldapdb { * */ -static char * krb5kdcentry_attrs[] = { +static char * krb5kdcentry_attrs[] = { "cn", "createTimestamp", "creatorsName", @@ -121,8 +119,9 @@ LDAP_no_size_limit(krb5_context context, LDAP *lp) ret = ldap_set_option(lp, LDAP_OPT_SIZELIMIT, (const void *)&limit); if (ret != LDAP_SUCCESS) { - krb5_set_error_string(context, "ldap_set_option: %s", - ldap_err2string(ret)); + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "ldap_set_option: %s", + ldap_err2string(ret)); return HDB_ERR_BADVERSION; } return 0; @@ -222,7 +221,7 @@ LDAP_addmod_len(LDAPMod *** modlist, int modop, const char *attribute, (*modlist)[cMods]->mod_bvalues = bv; - bv[i] = ber_memalloc(sizeof(*bv));; + bv[i] = ber_memalloc(sizeof(**bv));; if (bv[i] == NULL) return ENOMEM; @@ -295,8 +294,9 @@ LDAP_addmod_integer(krb5_context context, ret = asprintf(&buf, "%ld", l); if (ret < 0) { - krb5_set_error_string(context, "asprintf: out of memory:"); - return ret; + krb5_set_error_message(context, ENOMEM, + "asprintf: out of memory:"); + return ENOMEM; } ret = LDAP_addmod(mods, modop, attribute, buf); free (buf); @@ -307,38 +307,40 @@ static krb5_error_code LDAP_get_string_value(HDB * db, LDAPMessage * entry, const char *attribute, char **ptr) { - char **vals; - int ret; + struct berval **vals; - vals = ldap_get_values(HDB2LDAP(db), entry, (char *) attribute); - if (vals == NULL) { + vals = ldap_get_values_len(HDB2LDAP(db), entry, attribute); + if (vals == NULL || vals[0] == NULL) { *ptr = NULL; return HDB_ERR_NOENTRY; } - *ptr = strdup(vals[0]); - if (*ptr == NULL) - ret = ENOMEM; - else - ret = 0; + *ptr = malloc(vals[0]->bv_len + 1); + if (*ptr == NULL) { + ldap_value_free_len(vals); + return ENOMEM; + } - ldap_value_free(vals); + memcpy(*ptr, vals[0]->bv_val, vals[0]->bv_len); + (*ptr)[vals[0]->bv_len] = 0; - return ret; + ldap_value_free_len(vals); + + return 0; } static krb5_error_code LDAP_get_integer_value(HDB * db, LDAPMessage * entry, const char *attribute, int *ptr) { - char **vals; - - vals = ldap_get_values(HDB2LDAP(db), entry, (char *) attribute); - if (vals == NULL) - return HDB_ERR_NOENTRY; + krb5_error_code ret; + char *val; - *ptr = atoi(vals[0]); - ldap_value_free(vals); + ret = LDAP_get_string_value(db, entry, attribute, &val); + if (ret) + return ret; + *ptr = atoi(val); + free(val); return 0; } @@ -369,6 +371,14 @@ LDAP_get_generalized_time_value(HDB * db, LDAPMessage * entry, return 0; } +static int +bervalstrcmp(struct berval *v, const char *str) +{ + size_t len = strlen(str); + return (v->bv_len == len) && strncasecmp(str, (char *)v->bv_val, len) == 0; +} + + static krb5_error_code LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, LDAPMessage * msg, LDAPMod *** pmods) @@ -386,40 +396,39 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, krb5_boolean is_heimdal_entry = FALSE; krb5_boolean is_heimdal_principal = FALSE; - char **values; + struct berval **vals; *pmods = NULL; if (msg != NULL) { - ret = LDAP_message2entry(context, db, msg, &orig); + ret = LDAP_message2entry(context, db, msg, 0, &orig); if (ret) goto out; is_new_entry = FALSE; - - values = ldap_get_values(HDB2LDAP(db), msg, "objectClass"); - if (values) { - int num_objectclasses = ldap_count_values(values); + + vals = ldap_get_values_len(HDB2LDAP(db), msg, "objectClass"); + if (vals) { + int num_objectclasses = ldap_count_values_len(vals); for (i=0; i < num_objectclasses; i++) { - if (strcasecmp(values[i], "sambaSamAccount") == 0) { + if (bervalstrcmp(vals[i], "sambaSamAccount")) is_samba_account = TRUE; - } else if (strcasecmp(values[i], structural_object) == 0) { + else if (bervalstrcmp(vals[i], structural_object)) is_account = TRUE; - } else if (strcasecmp(values[i], "krb5Principal") == 0) { + else if (bervalstrcmp(vals[i], "krb5Principal")) is_heimdal_principal = TRUE; - } else if (strcasecmp(values[i], "krb5KDCEntry") == 0) { + else if (bervalstrcmp(vals[i], "krb5KDCEntry")) is_heimdal_entry = TRUE; - } } - ldap_value_free(values); + ldap_value_free_len(vals); } /* * If this is just a "account" entry and no other objectclass * is hanging on this entry, it's really a new entry. */ - if (is_samba_account == FALSE && is_heimdal_principal == FALSE && + if (is_samba_account == FALSE && is_heimdal_principal == FALSE && is_heimdal_entry == FALSE) { if (is_account == TRUE) { is_new_entry = TRUE; @@ -440,10 +449,10 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", "top"); if (ret) goto out; - + /* account is the structural object class */ if (is_account == FALSE) { - ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", + ret = LDAP_addmod(&mods, LDAP_MOD_ADD, "objectClass", structural_object); is_account = TRUE; if (ret) @@ -461,7 +470,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, goto out; } - if (is_new_entry || + if (is_new_entry || krb5_principal_compare(context, ent->entry.principal, orig.entry.principal) == FALSE) { @@ -495,7 +504,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, if (is_heimdal_entry && (ent->entry.kvno != orig.entry.kvno || is_new_entry)) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, - "krb5KeyVersionNumber", + "krb5KeyVersionNumber", ent->entry.kvno); if (ret) goto out; @@ -514,7 +523,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, if (ent->entry.valid_end) { if (orig.entry.valid_end == NULL || (*(ent->entry.valid_end) != *(orig.entry.valid_end))) { - if (is_heimdal_entry) { + if (is_heimdal_entry) { ret = LDAP_addmod_generalized_time(&mods, LDAP_MOD_REPLACE, "krb5ValidEnd", ent->entry.valid_end); @@ -523,7 +532,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, } if (is_samba_account) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, - "sambaKickoffTime", + "sambaKickoffTime", *(ent->entry.valid_end)); if (ret) goto out; @@ -543,7 +552,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, if (is_samba_account) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, - "sambaPwdMustChange", + "sambaPwdMustChange", *(ent->entry.pw_end)); if (ret) goto out; @@ -556,7 +565,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, if (is_samba_account && ent->entry.last_pw_change) { if (orig.entry.last_pw_change == NULL || (*(ent->entry.last_pw_change) != *(orig.entry.last_pw_change))) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, - "sambaPwdLastSet", + "sambaPwdLastSet", *(ent->entry.last_pw_change)); if (ret) goto out; @@ -569,7 +578,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, || (*(ent->entry.max_life) != *(orig.entry.max_life))) { ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, - "krb5MaxLife", + "krb5MaxLife", *(ent->entry.max_life)); if (ret) goto out; @@ -602,9 +611,9 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, /* Remove keys if they exists, and then replace keys. */ if (!is_new_entry && orig.entry.keys.len > 0) { - values = ldap_get_values(HDB2LDAP(db), msg, "krb5Key"); - if (values) { - ldap_value_free(values); + vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5Key"); + if (vals) { + ldap_value_free_len(vals); ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5Key", NULL); if (ret) @@ -618,38 +627,43 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { char *ntHexPassword; char *nt; - + time_t now = time(NULL); + /* the key might have been 'sealed', but samba passwords are clear in the directory */ ret = hdb_unseal_key(context, db, &ent->entry.keys.val[i]); if (ret) goto out; - + nt = ent->entry.keys.val[i].key.keyvalue.data; /* store in ntPassword, not krb5key */ ret = hex_encode(nt, 16, &ntHexPassword); if (ret < 0) { - krb5_set_error_string(context, "hdb-ldap: failed to " - "hex encode key"); ret = ENOMEM; + krb5_set_error_message(context, ret, "hdb-ldap: failed to " + "hex encode key"); goto out; } - ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "sambaNTPassword", + ret = LDAP_addmod(&mods, LDAP_MOD_REPLACE, "sambaNTPassword", ntHexPassword); free(ntHexPassword); if (ret) goto out; - + ret = LDAP_addmod_integer(context, &mods, LDAP_MOD_REPLACE, + "sambaPwdLastSet", now); + if (ret) + goto out; + /* have to kill the LM passwod if it exists */ - values = ldap_get_values(HDB2LDAP(db), msg, "sambaLMPassword"); - if (values) { - ldap_value_free(values); + vals = ldap_get_values_len(HDB2LDAP(db), msg, "sambaLMPassword"); + if (vals) { + ldap_value_free_len(vals); ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "sambaLMPassword", NULL); if (ret) goto out; } - + } else if (is_heimdal_entry) { unsigned char *buf; size_t len, buf_size; @@ -670,15 +684,15 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, if (ent->entry.etypes) { int add_krb5EncryptionType = 0; - /* + /* * Only add/modify krb5EncryptionType if it's a new heimdal * entry or krb5EncryptionType already exists on the entry. */ if (!is_new_entry) { - values = ldap_get_values(HDB2LDAP(db), msg, "krb5EncryptionType"); - if (values) { - ldap_value_free(values); + vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType"); + if (vals) { + ldap_value_free_len(vals); ret = LDAP_addmod(&mods, LDAP_MOD_DELETE, "krb5EncryptionType", NULL); if (ret) @@ -690,7 +704,7 @@ LDAP_entry2mods(krb5_context context, HDB * db, hdb_entry_ex * ent, if (add_krb5EncryptionType) { for (i = 0; i < ent->entry.etypes->len; i++) { - if (is_samba_account && + if (is_samba_account && ent->entry.keys.val[i].key.keytype == ETYPE_ARCFOUR_HMAC_MD5) { ; @@ -730,20 +744,22 @@ LDAP_dn2principal(krb5_context context, HDB * db, const char *dn, krb5_error_code ret; int rc; const char *filter = "(objectClass=krb5Principal)"; - char **values; LDAPMessage *res = NULL, *e; + char *p; ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) goto out; - rc = ldap_search_s(HDB2LDAP(db), dn, LDAP_SCOPE_SUBTREE, - filter, krb5principal_attrs, - 0, &res); + rc = ldap_search_ext_s(HDB2LDAP(db), dn, LDAP_SCOPE_SUBTREE, + filter, krb5principal_attrs, 0, + NULL, NULL, NULL, + 0, &res); if (check_ldap(context, db, rc)) { - krb5_set_error_string(context, "ldap_search_s: filter: %s error: %s", - filter, ldap_err2string(rc)); ret = HDB_ERR_NOENTRY; + krb5_set_error_message(context, ret, "ldap_search_ext_s: " + "filter: %s error: %s", + filter, ldap_err2string(rc)); goto out; } @@ -753,14 +769,14 @@ LDAP_dn2principal(krb5_context context, HDB * db, const char *dn, goto out; } - values = ldap_get_values(HDB2LDAP(db), e, "krb5PrincipalName"); - if (values == NULL) { + ret = LDAP_get_string_value(db, e, "krb5PrincipalName", &p); + if (ret) { ret = HDB_ERR_NOENTRY; goto out; } - ret = krb5_parse_name(context, values[0], principal); - ldap_value_free(values); + ret = krb5_parse_name(context, p, principal); + free(p); out: if (res) @@ -769,6 +785,49 @@ LDAP_dn2principal(krb5_context context, HDB * db, const char *dn, return ret; } +static int +need_quote(unsigned char c) +{ + return (c & 0x80) || + (c < 32) || + (c == '(') || + (c == ')') || + (c == '*') || + (c == '\\') || + (c == 0x7f); +} + +const static char hexchar[] = "0123456789ABCDEF"; + +static krb5_error_code +escape_value(krb5_context context, const unsigned char *unquoted, char **quoted) +{ + size_t i, len; + + for (i = 0, len = 0; unquoted[i] != '\0'; i++, len++) { + if (need_quote((unsigned char)unquoted[i])) + len += 2; + } + + *quoted = malloc(len + 1); + if (*quoted == NULL) { + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); + return ENOMEM; + } + + for (i = 0; unquoted[0] ; unquoted++) { + if (need_quote((unsigned char *)unquoted[0])) { + (*quoted)[i++] = '\\'; + (*quoted)[i++] = hexchar[(unquoted[0] >> 4) & 0xf]; + (*quoted)[i++] = hexchar[(unquoted[0] ) & 0xf]; + } else + (*quoted)[i++] = (char)unquoted[0]; + } + (*quoted)[i] = '\0'; + return 0; +} + + static krb5_error_code LDAP__lookup_princ(krb5_context context, HDB *db, @@ -778,18 +837,29 @@ LDAP__lookup_princ(krb5_context context, { krb5_error_code ret; int rc; - char *filter = NULL; + char *quote, *filter = NULL; ret = LDAP__connect(context, db); if (ret) return ret; + /* + * Quote searches that contain filter language, this quote + * searches for *@REALM, which takes very long time. + */ + + ret = escape_value(context, princname, "e); + if (ret) + goto out; + rc = asprintf(&filter, "(&(objectClass=krb5Principal)(krb5PrincipalName=%s))", - princname); + quote); + free(quote); + if (rc < 0) { - krb5_set_error_string(context, "asprintf: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } @@ -797,12 +867,16 @@ LDAP__lookup_princ(krb5_context context, if (ret) goto out; - rc = ldap_search_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, filter, - krb5kdcentry_attrs, 0, msg); + rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db), + LDAP_SCOPE_SUBTREE, filter, + krb5kdcentry_attrs, 0, + NULL, NULL, NULL, + 0, msg); if (check_ldap(context, db, rc)) { - krb5_set_error_string(context, "ldap_search_s: filter: %s - error: %s", - filter, ldap_err2string(rc)); ret = HDB_ERR_NOENTRY; + krb5_set_error_message(context, ret, "ldap_search_ext_s: " + "filter: %s - error: %s", + filter, ldap_err2string(rc)); goto out; } @@ -811,27 +885,34 @@ LDAP__lookup_princ(krb5_context context, filter = NULL; ldap_msgfree(*msg); *msg = NULL; - + + ret = escape_value(context, userid, "e); + if (ret) + goto out; + rc = asprintf(&filter, "(&(|(objectClass=sambaSamAccount)(objectClass=%s))(uid=%s))", - structural_object, userid); + structural_object, quote); + free(quote); if (rc < 0) { - krb5_set_error_string(context, "asprintf: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "asprintf: out of memory"); goto out; } - + ret = LDAP_no_size_limit(context, HDB2LDAP(db)); if (ret) goto out; - rc = ldap_search_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, - filter, krb5kdcentry_attrs, 0, msg); + rc = ldap_search_ext_s(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, + filter, krb5kdcentry_attrs, 0, + NULL, NULL, NULL, + 0, msg); if (check_ldap(context, db, rc)) { - krb5_set_error_string(context, - "ldap_search_s: filter: %s error: %s", - filter, ldap_err2string(rc)); ret = HDB_ERR_NOENTRY; + krb5_set_error_message(context, ret, + "ldap_search_ext_s: filter: %s error: %s", + filter, ldap_err2string(rc)); goto out; } } @@ -889,14 +970,13 @@ LDAP_principal2message(krb5_context context, HDB * db, */ static krb5_error_code LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, - hdb_entry_ex * ent) + int flags, hdb_entry_ex * ent) { char *unparsed_name = NULL, *dn = NULL, *ntPasswordIN = NULL; char *samba_acct_flags = NULL; - unsigned long tmp; struct berval **keys; - char **values; - int tmp_time, i, ret, have_arcfour = 0; + struct berval **vals; + int tmp, tmp_time, i, ret, have_arcfour = 0; memset(ent, 0, sizeof(*ent)); ent->entry.flags = int2HDBFlags(0); @@ -914,7 +994,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, if (ret) goto out; } else { - krb5_set_error_string(context, "hdb-ldap: ldap entry missing" + krb5_set_error_message(context, HDB_ERR_NOENTRY, + "hdb-ldap: ldap entry missing" "principal name"); return HDB_ERR_NOENTRY; } @@ -938,8 +1019,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ent->entry.keys.len = ldap_count_values_len(keys); ent->entry.keys.val = (Key *) calloc(ent->entry.keys.len, sizeof(Key)); if (ent->entry.keys.val == NULL) { - krb5_set_error_string(context, "calloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "calloc: out of memory"); goto out; } for (i = 0; i < ent->entry.keys.len; i++) { @@ -962,27 +1043,39 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, #endif } - values = ldap_get_values(HDB2LDAP(db), msg, "krb5EncryptionType"); - if (values != NULL) { + vals = ldap_get_values_len(HDB2LDAP(db), msg, "krb5EncryptionType"); + if (vals != NULL) { int i; ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes))); if (ent->entry.etypes == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret,"malloc: out of memory"); goto out; } - ent->entry.etypes->len = ldap_count_values(values); + ent->entry.etypes->len = ldap_count_values_len(vals); ent->entry.etypes->val = calloc(ent->entry.etypes->len, sizeof(int)); if (ent->entry.etypes->val == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + ent->entry.etypes->len = 0; goto out; } for (i = 0; i < ent->entry.etypes->len; i++) { - ent->entry.etypes->val[i] = atoi(values[i]); + char *buf; + + buf = malloc(vals[i]->bv_len + 1); + if (buf == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + memcpy(buf, vals[i]->bv_val, vals[i]->bv_len); + buf[vals[i]->bv_len] = '\0'; + ent->entry.etypes->val[i] = atoi(buf); + free(buf); } - ldap_value_free(values); + ldap_value_free_len(vals); } for (i = 0; i < ent->entry.keys.len; i++) { @@ -1003,8 +1096,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, (ent->entry.keys.len + 1) * sizeof(ent->entry.keys.val[0])); if (keys == NULL) { free(ntPasswordIN); - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ent->entry.keys.val = keys; @@ -1012,7 +1105,7 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ent->entry.keys.val[ent->entry.keys.len].key.keytype = ETYPE_ARCFOUR_HMAC_MD5; ret = krb5_data_alloc (&ent->entry.keys.val[ent->entry.keys.len].key.keyvalue, 16); if (ret) { - krb5_set_error_string(context, "malloc: out of memory"); + krb5_set_error_message(context, ret, "malloc: out of memory"); free(ntPasswordIN); ret = ENOMEM; goto out; @@ -1024,8 +1117,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, if (ent->entry.etypes == NULL) { ent->entry.etypes = malloc(sizeof(*(ent->entry.etypes))); if (ent->entry.etypes == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ent->entry.etypes->val = NULL; @@ -1037,16 +1130,16 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, break; /* If there is no ARCFOUR enctype, add one */ if (i == ent->entry.etypes->len) { - etypes = realloc(ent->entry.etypes->val, - (ent->entry.etypes->len + 1) * + etypes = realloc(ent->entry.etypes->val, + (ent->entry.etypes->len + 1) * sizeof(ent->entry.etypes->val[0])); if (etypes == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; - goto out; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; } ent->entry.etypes->val = etypes; - ent->entry.etypes->val[ent->entry.etypes->len] = + ent->entry.etypes->val[ent->entry.etypes->len] = ETYPE_ARCFOUR_HMAC_MD5; ent->entry.etypes->len++; } @@ -1059,37 +1152,38 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ent->entry.created_by.principal = NULL; - ret = LDAP_get_string_value(db, msg, "creatorsName", &dn); - if (ret == 0) { - if (LDAP_dn2principal(context, db, dn, &ent->entry.created_by.principal) - != 0) { - ent->entry.created_by.principal = NULL; + if (flags & HDB_F_ADMIN_DATA) { + ret = LDAP_get_string_value(db, msg, "creatorsName", &dn); + if (ret == 0) { + LDAP_dn2principal(context, db, dn, &ent->entry.created_by.principal); + free(dn); } - free(dn); - } - ent->entry.modified_by = (Event *) malloc(sizeof(Event)); - if (ent->entry.modified_by == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); - ret = ENOMEM; - goto out; - } - ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp", - &ent->entry.modified_by->time); - if (ret == 0) { - ret = LDAP_get_string_value(db, msg, "modifiersName", &dn); - if (LDAP_dn2principal(context, db, dn, &ent->entry.modified_by->principal)) - ent->entry.modified_by->principal = NULL; - free(dn); - } else { - free(ent->entry.modified_by); - ent->entry.modified_by = NULL; + ent->entry.modified_by = calloc(1, sizeof(*ent->entry.modified_by)); + if (ent->entry.modified_by == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + + ret = LDAP_get_generalized_time_value(db, msg, "modifyTimestamp", + &ent->entry.modified_by->time); + if (ret == 0) { + ret = LDAP_get_string_value(db, msg, "modifiersName", &dn); + if (ret == 0) { + LDAP_dn2principal(context, db, dn, &ent->entry.modified_by->principal); + free(dn); + } else { + free(ent->entry.modified_by); + ent->entry.modified_by = NULL; + } + } } ent->entry.valid_start = malloc(sizeof(*ent->entry.valid_start)); if (ent->entry.valid_start == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidStart", @@ -1099,11 +1193,11 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, free(ent->entry.valid_start); ent->entry.valid_start = NULL; } - + ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end)); if (ent->entry.valid_end == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5ValidEnd", @@ -1119,8 +1213,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, if (ent->entry.valid_end == NULL) { ent->entry.valid_end = malloc(sizeof(*ent->entry.valid_end)); if (ent->entry.valid_end == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } } @@ -1129,8 +1223,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); if (ent->entry.pw_end == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_generalized_time_value(db, msg, "krb5PasswordEnd", @@ -1141,13 +1235,34 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ent->entry.pw_end = NULL; } + ret = LDAP_get_integer_value(db, msg, "sambaPwdLastSet", &tmp_time); + if (ret == 0) { + time_t delta; + + if (ent->entry.pw_end == NULL) { + ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); + if (ent->entry.pw_end == NULL) { + ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); + goto out; + } + } + + delta = krb5_config_get_time_default(context, NULL, + 365 * 24 * 60 * 60, + "kadmin", + "password_lifetime", + NULL); + *ent->entry.pw_end = tmp_time + delta; + } + ret = LDAP_get_integer_value(db, msg, "sambaPwdMustChange", &tmp_time); if (ret == 0) { if (ent->entry.pw_end == NULL) { ent->entry.pw_end = malloc(sizeof(*ent->entry.pw_end)); if (ent->entry.pw_end == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } } @@ -1164,8 +1279,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ent->entry.max_life = malloc(sizeof(*ent->entry.max_life)); if (ent->entry.max_life == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxLife", &max_life); @@ -1181,8 +1296,8 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ent->entry.max_renew = malloc(sizeof(*ent->entry.max_renew)); if (ent->entry.max_renew == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "malloc: out of memory"); goto out; } ret = LDAP_get_integer_value(db, msg, "krb5MaxRenew", &max_renew); @@ -1193,18 +1308,9 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, *ent->entry.max_renew = max_renew; } - values = ldap_get_values(HDB2LDAP(db), msg, "krb5KDCFlags"); - if (values != NULL) { - errno = 0; - tmp = strtoul(values[0], (char **) NULL, 10); - if (tmp == ULONG_MAX && errno == ERANGE) { - krb5_set_error_string(context, "strtoul: could not convert flag"); - ret = ERANGE; - goto out; - } - } else { + ret = LDAP_get_integer_value(db, msg, "krb5KDCFlags", &tmp); + if (ret) tmp = 0; - } ent->entry.flags = int2HDBFlags(tmp); @@ -1212,29 +1318,29 @@ LDAP_message2entry(krb5_context context, HDB * db, LDAPMessage * msg, ret = LDAP_get_string_value(db, msg, "sambaAcctFlags", &samba_acct_flags); if (ret == 0) { /* parse the [UXW...] string: - - 'N' No password - 'D' Disabled - 'H' Homedir required - 'T' Temp account. - 'U' User account (normal) - 'M' MNS logon user account - what is this ? - 'W' Workstation account - 'S' Server account - 'L' Locked account - 'X' No Xpiry on password - 'I' Interdomain trust account - - */ - + + 'N' No password + 'D' Disabled + 'H' Homedir required + 'T' Temp account. + 'U' User account (normal) + 'M' MNS logon user account - what is this ? + 'W' Workstation account + 'S' Server account + 'L' Locked account + 'X' No Xpiry on password + 'I' Interdomain trust account + + */ + int i; int flags_len = strlen(samba_acct_flags); if (flags_len < 2) goto out2; - if (samba_acct_flags[0] != '[' - || samba_acct_flags[flags_len - 1] != ']') + if (samba_acct_flags[0] != '[' + || samba_acct_flags[flags_len - 1] != ']') goto out2; /* Allow forwarding */ @@ -1307,7 +1413,7 @@ LDAP_close(krb5_context context, HDB * db) ldap_unbind_ext(HDB2LDAP(db), NULL, NULL); ((struct hdbldapdb *)db->hdb_db)->h_lp = NULL; } - + return 0; } @@ -1343,7 +1449,7 @@ LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry) break; case LDAP_RES_SEARCH_ENTRY: /* We have an entry. Parse it. */ - ret = LDAP_message2entry(context, db, e, entry); + ret = LDAP_message2entry(context, db, e, flags, entry); ldap_msgfree(e); break; case LDAP_RES_SEARCH_RESULT: @@ -1351,13 +1457,13 @@ LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry) parserc = ldap_parse_result(HDB2LDAP(db), e, NULL, NULL, NULL, NULL, NULL, 1); + ret = HDB_ERR_NOENTRY; if (parserc != LDAP_SUCCESS && parserc != LDAP_MORE_RESULTS_TO_RETURN) { - krb5_set_error_string(context, "ldap_parse_result: %s", - ldap_err2string(parserc)); - ldap_abandon(HDB2LDAP(db), msgid); + krb5_set_error_message(context, ret, "ldap_parse_result: %s", + ldap_err2string(parserc)); + ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL); } - ret = HDB_ERR_NOENTRY; HDBSETMSGID(db, -1); break; case LDAP_SERVER_DOWN: @@ -1369,7 +1475,7 @@ LDAP_seq(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry) default: /* Some unspecified error (timeout?). Abandon. */ ldap_msgfree(e); - ldap_abandon(HDB2LDAP(db), msgid); + ldap_abandon_ext(HDB2LDAP(db), msgid, NULL, NULL); ret = HDB_ERR_NOENTRY; HDBSETMSGID(db, -1); break; @@ -1402,10 +1508,11 @@ LDAP_firstkey(krb5_context context, HDB *db, unsigned flags, if (ret) return ret; - msgid = ldap_search(HDB2LDAP(db), HDB2BASE(db), + ret = ldap_search_ext(HDB2LDAP(db), HDB2BASE(db), LDAP_SCOPE_SUBTREE, "(|(objectClass=krb5Principal)(objectClass=sambaSamAccount))", - krb5kdcentry_attrs, 0); + krb5kdcentry_attrs, 0, + NULL, NULL, NULL, 0, &msgid); if (msgid < 0) return HDB_ERR_NOENTRY; @@ -1451,16 +1558,16 @@ LDAP__connect(krb5_context context, HDB * db) rc = ldap_initialize(&((struct hdbldapdb *)db->hdb_db)->h_lp, HDB2URL(db)); if (rc != LDAP_SUCCESS) { - krb5_set_error_string(context, "ldap_initialize: %s", - ldap_err2string(rc)); + krb5_set_error_message(context, HDB_ERR_NOENTRY, "ldap_initialize: %s", + ldap_err2string(rc)); return HDB_ERR_NOENTRY; } rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_PROTOCOL_VERSION, (const void *)&version); if (rc != LDAP_SUCCESS) { - krb5_set_error_string(context, "ldap_set_option: %s", - ldap_err2string(rc)); + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "ldap_set_option: %s", ldap_err2string(rc)); LDAP_close(context, db); return HDB_ERR_BADVERSION; } @@ -1468,8 +1575,8 @@ LDAP__connect(krb5_context context, HDB * db) rc = ldap_sasl_bind_s(HDB2LDAP(db), NULL, "EXTERNAL", &bv, NULL, NULL, NULL); if (rc != LDAP_SUCCESS) { - krb5_set_error_string(context, "ldap_sasl_bind_s: %s", - ldap_err2string(rc)); + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "ldap_sasl_bind_s: %s", ldap_err2string(rc)); LDAP_close(context, db); return HDB_ERR_BADVERSION; } @@ -1497,8 +1604,8 @@ LDAP_open(krb5_context context, HDB * db, int flags, mode_t mode) } static krb5_error_code -LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal, - unsigned flags, hdb_entry_ex * entry) +LDAP_fetch_kvno(krb5_context context, HDB * db, krb5_const_principal principal, + unsigned flags, krb5_kvno kvno, hdb_entry_ex * entry) { LDAPMessage *msg, *e; krb5_error_code ret; @@ -1513,7 +1620,7 @@ LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal, goto out; } - ret = LDAP_message2entry(context, db, e, entry); + ret = LDAP_message2entry(context, db, e, flags, entry); if (ret == 0) { if (db->hdb_master_key_set && (flags & HDB_F_DECRYPT)) { ret = hdb_unseal_keys(context, db, &entry->entry); @@ -1529,6 +1636,14 @@ LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal, } static krb5_error_code +LDAP_fetch(krb5_context context, HDB * db, krb5_const_principal principal, + unsigned flags, hdb_entry_ex * entry) +{ + return LDAP_fetch_kvno(context, db, principal, + flags & (~HDB_F_KVNO_SPECIFIED), 0, entry); +} + +static krb5_error_code LDAP_store(krb5_context context, HDB * db, unsigned flags, hdb_entry_ex * entry) { @@ -1561,8 +1676,8 @@ LDAP_store(krb5_context context, HDB * db, unsigned flags, if (e == NULL) { ret = asprintf(&dn, "krb5PrincipalName=%s,%s", name, HDB2CREATE(db)); if (ret < 0) { - krb5_set_error_string(context, "asprintf: out of memory"); ret = ENOMEM; + krb5_set_error_message(context, ret, "asprintf: out of memory"); goto out; } } else if (flags & HDB_F_REPLACE) { @@ -1577,21 +1692,21 @@ LDAP_store(krb5_context context, HDB * db, unsigned flags, /* write entry into directory */ if (e == NULL) { /* didn't exist before */ - rc = ldap_add_s(HDB2LDAP(db), dn, mods); - errfn = "ldap_add_s"; + rc = ldap_add_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL ); + errfn = "ldap_add_ext_s"; } else { /* already existed, send deltas only */ - rc = ldap_modify_s(HDB2LDAP(db), dn, mods); - errfn = "ldap_modify_s"; + rc = ldap_modify_ext_s(HDB2LDAP(db), dn, mods, NULL, NULL ); + errfn = "ldap_modify_ext_s"; } if (check_ldap(context, db, rc)) { char *ld_error = NULL; ldap_get_option(HDB2LDAP(db), LDAP_OPT_ERROR_STRING, &ld_error); - krb5_set_error_string(context, "%s: %s (DN=%s) %s: %s", - errfn, name, dn, ldap_err2string(rc), ld_error); ret = HDB_ERR_CANT_LOCK_DB; + krb5_set_error_message(context, ret, "%s: %s (DN=%s) %s: %s", + errfn, name, dn, ldap_err2string(rc), ld_error); } else ret = 0; @@ -1635,17 +1750,17 @@ LDAP_remove(krb5_context context, HDB *db, krb5_const_principal principal) rc = ldap_set_option(HDB2LDAP(db), LDAP_OPT_SIZELIMIT, (const void *)&limit); if (rc != LDAP_SUCCESS) { - krb5_set_error_string(context, "ldap_set_option: %s", - ldap_err2string(rc)); ret = HDB_ERR_BADVERSION; + krb5_set_error_message(context, ret, "ldap_set_option: %s", + ldap_err2string(rc)); goto out; } - rc = ldap_delete_s(HDB2LDAP(db), dn); + rc = ldap_delete_ext_s(HDB2LDAP(db), dn, NULL, NULL ); if (check_ldap(context, db, rc)) { - krb5_set_error_string(context, "ldap_delete_s: %s", - ldap_err2string(rc)); ret = HDB_ERR_CANT_LOCK_DB; + krb5_set_error_message(context, ret, "ldap_delete_ext_s: %s", + ldap_err2string(rc)); } else ret = 0; @@ -1680,7 +1795,7 @@ LDAP_destroy(krb5_context context, HDB * db) return ret; } -krb5_error_code +static krb5_error_code hdb_ldap_common(krb5_context context, HDB ** db, const char *search_base, @@ -1690,40 +1805,40 @@ hdb_ldap_common(krb5_context context, const char *create_base = NULL; if (search_base == NULL && search_base[0] == '\0') { - krb5_set_error_string(context, "ldap search base not configured"); + krb5_set_error_message(context, ENOMEM, "ldap search base not configured"); return ENOMEM; /* XXX */ } if (structural_object == NULL) { const char *p; - p = krb5_config_get_string(context, NULL, "kdc", + p = krb5_config_get_string(context, NULL, "kdc", "hdb-ldap-structural-object", NULL); if (p == NULL) p = default_structural_object; structural_object = strdup(p); if (structural_object == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } } - samba_forwardable = + samba_forwardable = krb5_config_get_bool_default(context, NULL, TRUE, "kdc", "hdb-samba-forwardable", NULL); *db = calloc(1, sizeof(**db)); if (*db == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } memset(*db, 0, sizeof(**db)); h = calloc(1, sizeof(*h)); if (h == NULL) { - krb5_set_error_string(context, "malloc: out of memory"); free(*db); *db = NULL; + krb5_set_error_message(context, ENOMEM, "malloc: out of memory"); return ENOMEM; } (*db)->hdb_db = h; @@ -1731,8 +1846,8 @@ hdb_ldap_common(krb5_context context, /* XXX */ if (asprintf(&(*db)->hdb_name, "ldap:%s", search_base) == -1) { LDAP_destroy(context, *db); - krb5_set_error_string(context, "strdup: out of memory"); *db = NULL; + krb5_set_error_message(context, ENOMEM, "strdup: out of memory"); return ENOMEM; } @@ -1740,12 +1855,12 @@ hdb_ldap_common(krb5_context context, h->h_base = strdup(search_base); if (h->h_url == NULL || h->h_base == NULL) { LDAP_destroy(context, *db); - krb5_set_error_string(context, "strdup: out of memory"); *db = NULL; + krb5_set_error_message(context, ENOMEM, "strdup: out of memory"); return ENOMEM; } - create_base = krb5_config_get_string(context, NULL, "kdc", + create_base = krb5_config_get_string(context, NULL, "kdc", "hdb-ldap-create-base", NULL); if (create_base == NULL) create_base = h->h_base; @@ -1753,16 +1868,17 @@ hdb_ldap_common(krb5_context context, h->h_createbase = strdup(create_base); if (h->h_createbase == NULL) { LDAP_destroy(context, *db); - krb5_set_error_string(context, "strdup: out of memory"); *db = NULL; + krb5_set_error_message(context, ENOMEM, "strdup: out of memory"); return ENOMEM; } (*db)->hdb_master_key_set = 0; (*db)->hdb_openp = 0; + (*db)->hdb_capability_flags = 0; (*db)->hdb_open = LDAP_open; (*db)->hdb_close = LDAP_close; - (*db)->hdb_fetch = LDAP_fetch; + (*db)->hdb_fetch_kvno = LDAP_fetch_kvno; (*db)->hdb_store = LDAP_store; (*db)->hdb_remove = LDAP_remove; (*db)->hdb_firstkey = LDAP_firstkey; @@ -1792,14 +1908,15 @@ hdb_ldapi_create(krb5_context context, HDB ** db, const char *arg) asprintf(&p, "ldapi:%s", arg); if (p == NULL) { - krb5_set_error_string(context, "out of memory"); *db = NULL; + krb5_set_error_message(context, ENOMEM, "out of memory"); return ENOMEM; } search_base = strchr(p + strlen("ldapi://"), ':'); if (search_base == NULL) { - krb5_set_error_string(context, "search base missing"); *db = NULL; + krb5_set_error_message(context, HDB_ERR_BADVERSION, + "search base missing"); return HDB_ERR_BADVERSION; } *search_base = '\0'; |
