Use asn1c helpers to encode/decode the getkeytab control

Replaces manual encoding with automatically generated code.

Fixes:
https://fedorahosted.org/freeipa/ticket/4718
https://fedorahosted.org/freeipa/ticket/4728

Reviewed-By: Alexander Bokovoy <abokovoy@redhat.com>
Reviewed-By: Nathaniel McCallum <npmccallum@redhat.com>
This commit is contained in:
Simo Sorce 2014-11-17 15:19:57 -05:00
parent c6afc489a1
commit b1a30bff04
7 changed files with 107 additions and 396 deletions

View File

@ -76,6 +76,7 @@ client: client-autogen
bootstrap-autogen: version-update client-autogen
@echo "Building IPA $(IPA_VERSION)"
cd asn1; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi
cd daemons; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR) --with-openldap; fi
cd install; if [ ! -e Makefile ]; then ../autogen.sh --prefix=/usr --sysconfdir=/etc --localstatedir=/var --libdir=$(LIBDIR); fi

View File

@ -5,6 +5,7 @@ AC_INIT([ipa-server],
[https://hosted.fedoraproject.org/projects/freeipa/newticket])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SUBDIRS([../asn1])
AM_INIT_AUTOMAKE([foreign])
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES])
@ -305,6 +306,7 @@ AC_SUBST(LDFLAGS)
AC_CONFIG_FILES([
Makefile
../asn1/Makefile
ipa-kdb/Makefile
ipa-sam/Makefile
ipa-otpd/Makefile

View File

@ -6,6 +6,7 @@ KRB5_UTIL_DIR = ../../../util
KRB5_UTIL_SRCS = $(KRB5_UTIL_DIR)/ipa_krb5.c \
$(KRB5_UTIL_DIR)/ipa_pwd.c \
$(KRB5_UTIL_DIR)/ipa_pwd_ntlm.c
ASN1_UTIL_DIR=../../../asn1
AM_CPPFLAGS = \
-I. \
@ -13,6 +14,7 @@ AM_CPPFLAGS = \
-I$(srcdir)/../libotp \
-I$(PLUGIN_COMMON_DIR) \
-I$(KRB5_UTIL_DIR) \
-I$(ASN1_UTIL_DIR) \
-I$(COMMON_BER_DIR) \
-DPREFIX=\""$(prefix)"\" \
-DBINDIR=\""$(bindir)"\" \
@ -38,7 +40,10 @@ AM_LDFLAGS = \
# Plugin Binary
plugindir = $(libdir)/dirsrv/plugins
plugin_LTLIBRARIES = libipa_pwd_extop.la
libipa_pwd_extop_la_LIBADD = $(builddir)/../libotp/libotp.la
libipa_pwd_extop_la_LIBADD = \
$(builddir)/../libotp/libotp.la \
$(ASN1_UTIL_DIR)/libipaasn1.la \
$(NULL)
libipa_pwd_extop_la_SOURCES = \
authcfg.c \
common.c \

View File

@ -40,6 +40,7 @@
#include "ipapwd.h"
#include "util.h"
#include "authcfg.h"
#include "ipa_asn1.h"
/*
* Password Modify - LDAP Extended Operation.
@ -1310,31 +1311,7 @@ free_and_return:
return SLAPI_PLUGIN_EXTENDED_SENT_RESULT;
}
/* Format of getkeytab request
*
* KeytabGetRequest ::= CHOICE {
* newkeys [0] Newkeys,
* curkeys [1] CurrentKeys,
* reply [2] Reply
* }
*
* NewKeys ::= SEQUENCE {
* serviceIdentity [0] OCTET STRING,
* enctypes [1] SEQUENCE OF Int16
* password [2] OCTET STRING OPTIONAL,
* }
*
* CurrentKeys ::= SEQUENCE {
* serviceIdentity [0] OCTET STRING,
* }
*/
#define GK_REQUEST_NEWKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0)
#define GK_REQUEST_CURKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
#define GKREQ_SVCNAME_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
#define GKREQ_ENCTYPES_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
#define GKREQ_PASSWORD_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2)
/* decode a getkeytab control request using libipaasn1 helpers */
static int decode_getkeytab_request(struct berval *extop, bool *wantold,
char **_svcname, char **_password,
krb5_key_salt_tuple **kenctypes,
@ -1342,96 +1319,44 @@ static int decode_getkeytab_request(struct berval *extop, bool *wantold,
{
int rc = LDAP_OPERATIONS_ERROR;
char *err_msg = NULL;
BerElement *ber = NULL;
ber_len_t tlen;
ber_tag_t rtag;
ber_tag_t ttag;
ber_tag_t ctag;
char *svcname = NULL;
char *password = NULL;
ber_int_t enctype;
long *etypes = NULL;
int numtypes = 0;
krb5_key_salt_tuple *enctypes = NULL;
int num = 0;
bool newkt;
bool ret;
int i;
ber = ber_init(extop);
if (ber == NULL) {
err_msg = "KeytabGet Request decode failed.\n";
ret = ipaasn1_dec_getkt(extop->bv_val, extop->bv_len, &newkt,
&svcname, &password, &etypes, &numtypes);
if (!ret) {
err_msg = "Failed to decode GetKeytab Control.\n";
rc = LDAP_PROTOCOL_ERROR;
goto done;
}
/* check this is a request */
rtag = ber_peek_tag(ber, &tlen);
if (rtag != GK_REQUEST_NEWKEYS && rtag != GK_REQUEST_CURKEYS) {
LOG_FATAL("ber_peek_tag failed, wrong request type\n");
err_msg = "Invalid payload.\n";
rc = LDAP_PROTOCOL_ERROR;
goto done;
}
/* ber parse code */
ttag = ber_scanf(ber, "{ta", &ctag, &svcname);
if (ttag == LBER_ERROR || ctag != GKREQ_SVCNAME_TAG) {
LOG_FATAL("ber_scanf failed to decode service name\n");
err_msg = "Invalid payload.\n";
rc = LDAP_PROTOCOL_ERROR;
goto done;
}
if (rtag == GK_REQUEST_CURKEYS) {
rc = LDAP_SUCCESS;
goto done;
}
ttag = ber_peek_tag(ber, &tlen);
if (ttag != GKREQ_ENCTYPES_TAG) {
LOG_FATAL("ber_peek_tag failed to find enctypes\n");
err_msg = "Invalid payload.\n";
rc = LDAP_PROTOCOL_ERROR;
goto done;
}
ttag = ber_peek_tag(ber, &tlen);
for (num = 0; ttag == LBER_INTEGER; num++) {
if ((num % 10) == 0) {
/* allocate space for at least 10 more enctypes */
enctypes = realloc(enctypes,
(num + 10) * sizeof(krb5_key_salt_tuple));
if (newkt) {
if (numtypes) {
enctypes = malloc(numtypes * sizeof(krb5_key_salt_tuple));
if (!enctypes) {
LOG_FATAL("allocation failed\n");
err_msg = "Internal error\n";
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
}
ttag = ber_scanf(ber, "i", &enctype);
if (ttag == LBER_ERROR) {
LOG_FATAL("ber_scanf failed to decode enctype\n");
err_msg = "Invalid payload.\n";
rc = LDAP_PROTOCOL_ERROR;
goto done;
}
enctypes[num].ks_enctype = enctype;
enctypes[num].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL;
ttag = ber_peek_tag(ber, &tlen);
}
/* ttag peek done as last step of the previous for loop */
if (ttag == GKREQ_PASSWORD_TAG) {
/* optional password present */
ttag = ber_scanf(ber, "a", &password);
if (ttag == LBER_ERROR) {
LOG_FATAL("ber_scanf failed to decode password\n");
err_msg = "Invalid payload.\n";
rc = LDAP_PROTOCOL_ERROR;
goto done;
for (i = 0; i < numtypes; i++) {
enctypes[i].ks_enctype = etypes[i];
enctypes[i].ks_salttype = KRB5_KDB_SALTTYPE_NORMAL;
}
}
}
rc = LDAP_SUCCESS;
done:
free(etypes);
if (rc != LDAP_SUCCESS) {
free(password);
free(svcname);
@ -1440,78 +1365,34 @@ done:
} else {
*_password = password;
*_svcname = svcname;
*wantold = (rtag == GK_REQUEST_CURKEYS);
*wantold = (newkt == false);
*kenctypes = enctypes;
*num_kenctypes = num;
*num_kenctypes = numtypes;
}
if (ber) ber_free(ber, 1);
return rc;
}
/* Format of getkeytab reply
*
* Reply ::= SEQUENCE {
* new_kvno Int32
* keys SEQUENCE OF KrbKey,
* }
*
* KrbKey ::= SEQUENCE {
* key [0] EncryptionKey,
* salt [1] KrbSalt OPTIONAL,
* s2kparams [2] OCTET STRING OPTIONAL,
* }
*
* EncryptionKey ::= SEQUENCE {
* keytype [0] Int32,
* keyvalue [1] OCTET STRING
* }
*
* KrbSalt ::= SEQUENCE {
* type [0] Int32,
* salt [1] OCTET STRING
* }
*/
#define GK_REPLY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2)
#define GKREP_KEY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0)
#define GKREP_SALT_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
#define GKREP_S2KPARAMS_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2)
#define GKREP_KEYTYPE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0)
#define GKREP_KEYVALUE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
#define GKREP_SALTTYPE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0)
#define GKREP_SALTVALUE_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
static int encode_getkeytab_reply(krb5_context krbctx,
krb5_keyblock *kmkey, int mkvno,
krb5_key_data *keys, int num_keys,
struct berval **_bvp)
{
int rc = LDAP_OPERATIONS_ERROR;
struct krb_key_salt ksdata[num_keys];
struct keys_container ksc = { num_keys, ksdata };
struct berval *bvp = NULL;
BerElement *ber = NULL;
ber_int_t kvno;
krb5_data plain = { 0 };
int kvno;
bool ret;
ber = ber_alloc();
if (!ber) {
LOG_OOM();
goto done;
}
memset(ksdata, '\0', num_keys * sizeof(struct krb_key_salt));
/* uses last key kvno */
kvno = keys[num_keys-1].key_data_kvno;
rc = ber_printf(ber, "t{i{", GK_REPLY_TAG, kvno);
if (rc == -1) {
rc = LDAP_OPERATIONS_ERROR;
LOG_FATAL("Failed to initiate key buffer\n");
goto done;
}
for (int i = 0; i < num_keys; i++) {
krb5_enc_data cipher = { 0 };
krb5_data plain = { 0 };
krb5_int16 plen;
void *p;
/* retrieve plain key */
memcpy(&plen, keys[i].key_data_contents[0], 2);
@ -1521,13 +1402,12 @@ static int encode_getkeytab_reply(krb5_context krbctx,
cipher.kvno = mkvno;
plain.length = le16toh(plen);
p = realloc(plain.data, plain.length);
if (!p) {
plain.data = malloc(plain.length);
if (!plain.data) {
LOG_FATAL("Failed to allocate plain buffer\n");
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
plain.data = p;
rc = krb5_c_decrypt(krbctx, kmkey, 0, 0, &cipher, &plain);
if (rc) {
@ -1536,68 +1416,37 @@ static int encode_getkeytab_reply(krb5_context krbctx,
goto done;
}
rc = ber_printf(ber,
"{t{tito}",
GKREP_KEY_TAG,
GKREP_KEYTYPE_TAG,
(ber_int_t)keys[i].key_data_type[0],
GKREP_KEYVALUE_TAG,
plain.data, (ber_len_t)plain.length);
if (rc == -1) {
LOG_FATAL("Failed to encode key data\n");
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
ksc.ksdata[i].enctype = keys[i].key_data_type[0];
ksc.ksdata[i].key.enctype = keys[i].key_data_type[0];
ksc.ksdata[i].key.contents = (void *)plain.data;
ksc.ksdata[i].key.length = plain.length;
/* if salt available, add it */
if (keys[i].key_data_length[1] != 0) {
rc = ber_printf(ber,
"t{tito}",
GKREP_SALT_TAG,
GKREP_SALTTYPE_TAG,
(ber_int_t)keys[i].key_data_type[1],
GKREP_SALTVALUE_TAG,
keys[i].key_data_contents[1],
(ber_len_t)keys[i].key_data_length[1]);
if (rc == -1) {
LOG_FATAL("Failed to encode salt data\n");
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
}
rc = ber_printf(ber, "}");
if (rc == -1) {
LOG_FATAL("Failed to encode data\n");
rc = LDAP_OPERATIONS_ERROR;
goto done;
ksc.ksdata[i].salttype = keys[i].key_data_type[1];
ksc.ksdata[i].salt.data = (void *)keys[i].key_data_contents[1];
ksc.ksdata[i].salt.length = keys[i].key_data_length[1];
}
}
rc = ber_printf(ber, "}}");
if (rc == -1) {
LOG_FATAL("Failed to terminate key buffer\n");
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
bvp = calloc(1, sizeof(struct berval));
if (!bvp) goto done;
rc = ber_flatten(ber, &bvp);
if (rc == -1) {
LOG_FATAL("Failed to encode key buffer\n");
rc = LDAP_OPERATIONS_ERROR;
goto done;
}
ret = ipaasn1_enc_getktreply(kvno, &ksc,
(void **)&bvp->bv_val, &bvp->bv_len);
if (!ret) goto done;
rc = LDAP_SUCCESS;
done:
for (int i = 0; i < ksc.nkeys; i ++) {
free(ksc.ksdata[i].key.contents);
}
if (rc != LDAP_SUCCESS) {
if (bvp) ber_bvfree(bvp);
} else {
*_bvp = bvp;
}
if (ber) ber_free(ber, 1);
free(plain.data);
return rc;
}

View File

@ -14,11 +14,13 @@ export AM_CFLAGS
KRB5_UTIL_DIR=../util
KRB5_UTIL_SRCS=$(KRB5_UTIL_DIR)/ipa_krb5.c
ASN1_UTIL_DIR=../asn1
AM_CPPFLAGS = \
-I. \
-I$(srcdir) \
-I$(KRB5_UTIL_DIR) \
-I$(ASN1_UTIL_DIR) \
-DPREFIX=\""$(prefix)"\" \
-DBINDIR=\""$(bindir)"\" \
-DLIBDIR=\""$(libdir)"\" \
@ -45,6 +47,7 @@ ipa_getkeytab_SOURCES = \
$(NULL)
ipa_getkeytab_LDADD = \
../asn1/libipaasn1.la \
$(KRB5_LIBS) \
$(OPENLDAP_LIBS) \
$(SASL_LIBS) \
@ -80,6 +83,7 @@ ipa_join_LDADD = \
$(NULL)
SUBDIRS = \
../asn1 \
ipaclient \
ipa-install \
man \

View File

@ -8,6 +8,7 @@ AC_PROG_LIBTOOL
AC_CONFIG_SRCDIR([ipaclient/__init__.py])
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_SUBDIRS([../asn1])
AM_INIT_AUTOMAKE([foreign])
@ -205,6 +206,7 @@ dnl ---------------------------------------------------------------------------
AC_CONFIG_FILES([
Makefile
../asn1/Makefile
ipaclient/Makefile
ipa-install/Makefile
man/Makefile

View File

@ -40,6 +40,7 @@
#include "config.h"
#include "ipa_krb5.h"
#include "ipa_asn1.h"
#include "ipa-client-common.h"
static int ldap_sasl_interact(LDAP *ld, unsigned flags, void *priv_data, void *sit)
@ -295,14 +296,15 @@ done:
return ret;
}
static BerElement *get_control_data(LDAPControl **list, const char *repoid)
static int find_control_data(LDAPControl **list, const char *repoid,
struct berval *data)
{
LDAPControl *control = NULL;
int i;
if (!list) {
fprintf(stderr, _("Missing reply control list!\n"));
return NULL;
return LDAP_OPERATIONS_ERROR;
}
for (i = 0; list[i]; i++) {
@ -312,10 +314,22 @@ static BerElement *get_control_data(LDAPControl **list, const char *repoid)
}
if (!control) {
fprintf(stderr, _("Missing reply control!\n"));
return NULL;
return LDAP_OPERATIONS_ERROR;
}
return ber_init(&control->ldctl_value);
*data = control->ldctl_value;
return LDAP_SUCCESS;
}
static BerElement *get_control_data(LDAPControl **list, const char *repoid)
{
struct berval data;
int ret;
ret = find_control_data(list, repoid, &data);
if (ret != LDAP_SUCCESS) return NULL;
return ber_init(&data);
}
static int ldap_set_keytab(krb5_context krbctx,
@ -435,124 +449,42 @@ error_out:
return -1;
}
/* Format of getkeytab control
*
* KeytabGetRequest ::= CHOICE {
* newkeys [0] Newkeys,
* curkeys [1] CurrentKeys,
* reply [2] Reply
* }
*
* NewKeys ::= SEQUENCE {
* serviceIdentity [0] OCTET STRING,
* enctypes [1] SEQUENCE OF Int16
* password [2] OCTET STRING OPTIONAL,
* }
*
* CurrentKeys ::= SEQUENCE {
* serviceIdentity [0] OCTET STRING,
* }
*
* Reply ::= SEQUENCE {
* new_kvno Int32
* keys SEQUENCE OF KrbKey,
* }
*
* KrbKey ::= SEQUENCE {
* key [0] EncryptionKey,
* salt [1] KrbSalt OPTIONAL,
* s2kparams [2] OCTET STRING OPTIONAL,
* }
*
* EncryptionKey ::= SEQUENCE {
* keytype [0] Int32,
* keyvalue [1] OCTET STRING
* }
*
* KrbSalt ::= SEQUENCE {
* type [0] Int32,
* salt [1] OCTET STRING
* }
*/
#define GK_REQUEST_NEWKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 0)
#define GK_REQUEST_CURKEYS (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
#define GKREQ_SVCNAME_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
#define GKREQ_ENCTYPES_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 1)
#define GKREQ_PASSWORD_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2)
/* use asn1c generated code to fill up control */
static struct berval *create_getkeytab_control(const char *svc_princ, bool gen,
const char *password,
struct krb_key_salt *encsalts,
int num_encsalts)
{
struct berval *bval = NULL;
BerElement *be;
ber_tag_t ctag;
ber_int_t e;
int ret, i;
be = ber_alloc_t(LBER_USE_DER);
if (!be) {
return NULL;
}
struct berval *result = NULL;
void *buffer = NULL;
size_t buflen;
long ets[num_encsalts];
bool ret;
int i;
if (gen) {
ctag = GK_REQUEST_NEWKEYS;
} else {
ctag = GK_REQUEST_CURKEYS;
}
ret = ber_printf(be, "t{ts", ctag, GKREQ_SVCNAME_TAG, svc_princ);
if (ret == -1) {
ber_free(be, 1);
goto done;
}
if (gen) {
ret = ber_printf(be, "t{", GKREQ_ENCTYPES_TAG);
if (ret == -1) {
ber_free(be, 1);
goto done;
}
for (i = 0; i < num_encsalts; i++) {
e = encsalts[i].enctype;
ret = ber_printf(be, "i", e);
if (ret == -1) {
ber_free(be, 1);
goto done;
}
}
ret = ber_printf(be, "}");
if (ret == -1) {
ber_free(be, 1);
goto done;
}
if (password) {
ret = ber_printf(be, "ts", GKREQ_PASSWORD_TAG, password);
if (ret == -1) {
ber_free(be, 1);
goto done;
}
ets[i] = encsalts[i].enctype;
}
}
ret = ipaasn1_enc_getkt(gen, svc_princ,
password, ets, num_encsalts,
&buffer, &buflen);
if (!ret) goto done;
ret = ber_printf(be, "}");
if (ret == -1) {
ber_free(be, 1);
goto done;
}
result = malloc(sizeof(struct berval));
if (!result) goto done;
ret = ber_flatten(be, &bval);
if (ret == -1) {
ber_free(be, 1);
goto done;
}
result->bv_val = buffer;
result->bv_len = buflen;
done:
ber_free(be, 1);
return bval;
if (result == NULL) {
if (buffer) {
free(buffer);
}
}
return result;
}
#define GK_REPLY_TAG (LBER_CLASS_CONTEXT | LBER_CONSTRUCTED | 2)
@ -571,13 +503,8 @@ static int ldap_get_keytab(krb5_context krbctx, bool generate, char *password,
struct berval *control = NULL;
LDAP *ld = NULL;
LDAPControl **srvctrl = NULL;
BerElement *ber = NULL;
ber_tag_t rtag;
ber_tag_t ctag;
ber_len_t tlen;
ber_int_t vno;
ber_int_t tint;
struct berval tbval;
struct berval data;
bool res;
int ret;
*err_msg = NULL;
@ -609,98 +536,19 @@ static int ldap_get_keytab(krb5_context krbctx, bool generate, char *password,
goto done;
}
ber = get_control_data(srvctrl, KEYTAB_GET_OID);
if (!ber) {
*err_msg = _("Failed to find or parse reply control!\n");
ret = find_control_data(srvctrl, KEYTAB_GET_OID, &data);
if (ret != LDAP_SUCCESS) goto done;
res = ipaasn1_dec_getktreply(data.bv_val, data.bv_len, kvno, keys);
if (!res) {
*err_msg = _("Failed to decode control reply!\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
rtag = ber_scanf(ber, "t{i{", &ctag, &vno);
if (rtag == LBER_ERROR || ctag != GK_REPLY_TAG) {
*err_msg = _("Failed to parse control head!\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
keys->nkeys = 0;
keys->ksdata = NULL;
rtag = ber_peek_tag(ber, &tlen);
for (int i = 0; rtag == LBER_SEQUENCE; i++) {
if ((i % 5) == 0) {
struct krb_key_salt *ksdata;
ksdata = realloc(keys->ksdata,
(i + 5) * sizeof(struct krb_key_salt));
if (!ksdata) {
*err_msg = _("Out of memory!\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
keys->ksdata = ksdata;
}
memset(&keys->ksdata[i], 0, sizeof(struct krb_key_salt));
keys->nkeys = i + 1;
rtag = ber_scanf(ber, "{t{io}", &ctag, &tint, &tbval);
if (rtag == LBER_ERROR || ctag != GKREP_KEY_TAG) {
*err_msg = _("Failed to parse enctype in key data!\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
keys->ksdata[i].enctype = tint;
keys->ksdata[i].key.enctype = tint;
keys->ksdata[i].key.length = tbval.bv_len;
keys->ksdata[i].key.contents = malloc(tbval.bv_len);
if (!keys->ksdata[i].key.contents) {
*err_msg = _("Out of memory!\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
memcpy(keys->ksdata[i].key.contents, tbval.bv_val, tbval.bv_len);
ber_memfree(tbval.bv_val);
rtag = ber_peek_tag(ber, &tlen);
if (rtag == GKREP_SALT_TAG) {
rtag = ber_scanf(ber, "t{io}", &ctag, &tint, &tbval);
if (rtag == LBER_ERROR) {
*err_msg = _("Failed to parse salt in key data!\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
keys->ksdata[i].salttype = tint;
keys->ksdata[i].salt.length = tbval.bv_len;
keys->ksdata[i].salt.data = malloc(tbval.bv_len);
if (!keys->ksdata[i].salt.data) {
*err_msg = _("Out of memory!\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
memcpy(keys->ksdata[i].salt.data, tbval.bv_val, tbval.bv_len);
ber_memfree(tbval.bv_val);
}
rtag = ber_scanf(ber, "}");
if (rtag == LBER_ERROR) {
*err_msg = _("Failed to parse ending of key data!\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
rtag = ber_peek_tag(ber, &tlen);
}
rtag = ber_scanf(ber, "}}");
if (rtag == LBER_ERROR) {
*err_msg = _("Failed to parse ending of control!\n");
ret = LDAP_OPERATIONS_ERROR;
goto done;
}
*kvno = vno;
ret = LDAP_SUCCESS;
done:
if (ber) ber_free(ber, 1);
if (ld) ldap_unbind_ext(ld, NULL, NULL);
if (control) ber_bvfree(control);
free(es);