[2903] in Kerberos
memory leaks
daemon@ATHENA.MIT.EDU (Glenn NoI Machin)
Fri Nov 19 16:57:54 1993
Date: Fri, 19 Nov 1993 14:28:13 -0700
From: Glenn NoI Machin <gmachin@somnet.sandia.gov>
To: krb5_bugs@MIT.EDU
Cc: kerberos@MIT.EDU
The folllowing memory leak was found in the pre-beta3 release
of krb5.
---------------------------------------------------------------------
File: lib/keytab/file/ktf_util.c routine: krb5_ktfileint_internal_read_entry
The problem had to do with not freeing ret_entry, when problems occurred. I
have provided the "fixed" code. The changes were extensive enough that just
marking the changes would take to long.....
krb5_error_code
krb5_ktfileint_internal_read_entry(id, entrypp, delete_point)
krb5_keytab id;
krb5_keytab_entry **entrypp;
krb5_int32 *delete_point;
{
register krb5_keytab_entry *ret_entry;
krb5_int16 count;
krb5_int16 princ_size;
register int i;
krb5_int32 size;
krb5_int32 start_pos;
krb5_error_code error;
char *tmpdata;
krb5_data *princ;
if (!(ret_entry = (krb5_keytab_entry *)calloc(1, sizeof(*ret_entry))))
return ENOMEM;
/* fseek to synchronise buffered I/O on the key table. */
if (fseek(KTFILEP(id), 0L, SEEK_CUR) < 0)
{
error = errno;
goto freeout;
}
do {
*delete_point = ftell(KTFILEP(id));
if (!xfread(&size, sizeof(size), 1, KTFILEP(id))) {
error = KRB5_KT_END;
goto freeout;
}
if (KTVERSION(id) != KRB5_KT_VNO_1)
size = ntohl(size);
if (size < 0) {
if (fseek(KTFILEP(id), -size, SEEK_CUR)) {
error = errno;
goto freeout;
}
}
} while (size < 0);
if (size == 0) {
error = KRB5_KT_END;
goto freeout;
}
start_pos = ftell(KTFILEP(id));
/* deal with guts of parsing... */
/* first, int16 with #princ components */
if (!xfread(&count, sizeof(count), 1, KTFILEP(id))){
error = KRB5_KT_END;
goto freeout;
}
if (KTVERSION(id) == KRB5_KT_VNO_1) {
count -= 1; /* V1 includes the realm in the count */
} else {
count = ntohs(count);
}
if (!count || (count < 0)){
error = KRB5_KT_END;
goto freeout;
}
ret_entry->principal = (krb5_principal)malloc(sizeof(krb5_principal_data));
if (!ret_entry->principal){
error = ENOMEM;
goto freeout;
}
ret_entry->principal->length = count;
ret_entry->principal->data = (krb5_data *)calloc(count, sizeof(krb5_data));
if (!ret_entry->principal->data) {
free(ret_entry->principal);
error = ENOMEM;
goto freeout;
}
/* Now, get the realm data */
if (!xfread(&princ_size, sizeof(princ_size), 1, KTFILEP(id))) {
error = KRB5_KT_END;
goto fail;
}
if (KTVERSION(id) != KRB5_KT_VNO_1)
princ_size = ntohs(princ_size);
if (!princ_size || (princ_size < 0)) {
error = KRB5_KT_END;
goto fail;
}
krb5_princ_set_realm_length(ret_entry->principal, princ_size);
tmpdata = malloc(princ_size+1);
if (!tmpdata) {
error = ENOMEM;
goto fail;
}
if (fread(tmpdata, 1, princ_size, KTFILEP(id)) != princ_size) {
free(tmpdata);
error = KRB5_KT_END;
goto fail;
}
tmpdata[princ_size] = 0; /* Some things might be expecting null */
/* termination... ``Be conservative in */
/* what you send out'' */
krb5_princ_set_realm_data(ret_entry->principal, tmpdata);
for (i = 0; i < count; i++) {
princ = krb5_princ_component(ret_entry->principal, i);
if (!xfread(&princ_size, sizeof(princ_size), 1, KTFILEP(id))) {
error = KRB5_KT_END;
goto fail;
}
if (KTVERSION(id) != KRB5_KT_VNO_1)
princ_size = ntohs(princ_size);
if (!princ_size || (princ_size < 0)) {
error = KRB5_KT_END;
goto fail;
}
princ->length = princ_size;
princ->data = malloc(princ_size+1);
if (!princ->data) {
error = ENOMEM;
goto fail;
}
if (!xfread(princ->data, sizeof(char), princ_size, KTFILEP(id))) {
error = KRB5_KT_END;
goto fail;
}
princ->data[princ_size] = 0; /* Null terminate */
}
/* read in the principal type, if we can get it */
if (KTVERSION(id) != KRB5_KT_VNO_1) {
if (!xfread(&ret_entry->principal->type,
sizeof(ret_entry->principal->type), 1, KTFILEP(id))) {
error = KRB5_KT_END;
goto fail;
}
ret_entry->principal->type = ntohl(ret_entry->principal->type);
}
/* read in the timestamp */
if (!xfread(&ret_entry->timestamp, sizeof(ret_entry->timestamp), 1, KTFILEP(id))) {
error = KRB5_KT_END;
goto fail;
}
if (KTVERSION(id) != KRB5_KT_VNO_1)
ret_entry->timestamp = ntohl(ret_entry->timestamp);
/* read in the version number */
if (!xfread(&ret_entry->vno, sizeof(ret_entry->vno), 1, KTFILEP(id))) {
error = KRB5_KT_END;
goto fail;
}
/* key type */
if (!xfread(&ret_entry->key.keytype, sizeof(ret_entry->key.keytype), 1,
KTFILEP(id))) {
error = KRB5_KT_END;
goto fail;
}
if (KTVERSION(id) != KRB5_KT_VNO_1)
ret_entry->key.keytype = ntohs(ret_entry->key.keytype);
/* key contents */
if (!xfread(&count, sizeof(count), 1, KTFILEP(id))) {
error = KRB5_KT_END;
goto fail;
}
if (KTVERSION(id) != KRB5_KT_VNO_1)
count = ntohs(count);
if (!count || (count < 0)) {
error = KRB5_KT_END;
goto fail;
}
ret_entry->key.length = count;
ret_entry->key.contents = (krb5_octet *)malloc(count);
if (!ret_entry->key.contents) {
error = ENOMEM;
goto fail;
}
if (!xfread(ret_entry->key.contents, sizeof(krb5_octet), count,
KTFILEP(id))) {
error = KRB5_KT_END;
goto fail;
}
*entrypp = ret_entry;
/*
* Reposition file pointer to the next inter-record length field.
*/
fseek(KTFILEP(id), start_pos + size, SEEK_SET);
return 0;
fail:
for (i = 0; i < ret_entry->principal->length; i++) {
princ = krb5_princ_component(ret_entry->principal, i);
if (princ->data)
free(princ->data);
}
free(ret_entry->principal->data);
free(ret_entry->principal);
freeout:
free(ret_entry);
return error;
}