static krb5_error_code ctx_iterate(krb5_context context, krb5_db2_context *dbc, krb5_error_code (*func)(krb5_pointer, krb5_db_entry *), krb5_pointer func_arg) { DB *db; DBT key, contents; krb5_data contdata; krb5_db_entry *entry; krb5_error_code retval, retval2; int dbret; retval = ctx_lock(context, dbc, KRB5_LOCKMODE_SHARED); if (retval) return retval; db = dbc->db; dbret = db->seq(db, &key, &contents, R_FIRST); while (dbret == 0) { contdata.data = contents.data; contdata.length = contents.size; retval = krb5_decode_princ_entry(context, &contdata, &entry); if (retval) break; retval = k5_mutex_unlock(krb5_db2_mutex); if (retval) break; retval = (*func)(func_arg, entry); krb5_dbe_free(context, entry); retval2 = k5_mutex_lock(krb5_db2_mutex); /* Note: If re-locking fails, the wrapper in db2_exp.c will still try to unlock it again. That would be a bug. Fix when integrating the locking better. */ if (retval) break; if (retval2) { retval = retval2; break; } dbret = db->seq(db, &key, &contents, R_NEXT); } switch (dbret) { case 1: case 0: break; case -1: default: retval = errno; } (void) ctx_unlock(context, dbc); return retval; }
krb5_error_code krb5_db2_delete_principal(krb5_context context, krb5_const_principal searchfor) { krb5_error_code retval; krb5_db_entry *entry; krb5_db2_context *db_ctx; DB *db; DBT key, contents; krb5_data keydata, contdata; int i, dbret; if (!k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; db_ctx = context->dal_handle->db_context; if ((retval = krb5_db2_lock(context, KRB5_LOCKMODE_EXCLUSIVE))) return (retval); if ((retval = krb5_db2_start_update(context))) { (void) krb5_db2_unlock(context); /* unlock write lock */ return (retval); } if ((retval = krb5_encode_princ_dbkey(context, &keydata, searchfor))) goto cleanup; key.data = keydata.data; key.size = keydata.length; db = db_ctx->db; dbret = (*db->get) (db, &key, &contents, 0); retval = errno; switch (dbret) { case 1: retval = KRB5_KDB_NOENTRY; /* Fall through. */ case -1: default: goto cleankey; case 0: ; } contdata.data = contents.data; contdata.length = contents.size; retval = krb5_decode_princ_entry(context, &contdata, &entry); if (retval) goto cleankey; /* Clear encrypted key contents */ for (i = 0; i < entry->n_key_data; i++) { if (entry->key_data[i].key_data_length[0]) { memset(entry->key_data[i].key_data_contents[0], 0, (unsigned) entry->key_data[i].key_data_length[0]); } } retval = krb5_encode_princ_entry(context, &contdata, entry); krb5_dbe_free(context, entry); if (retval) goto cleankey; contents.data = contdata.data; contents.size = contdata.length; dbret = (*db->put) (db, &key, &contents, 0); retval = dbret ? errno : 0; krb5_free_data_contents(context, &contdata); if (retval) goto cleankey; dbret = (*db->del) (db, &key, 0); retval = dbret ? errno : 0; cleankey: krb5_free_data_contents(context, &keydata); cleanup: (void) krb5_db2_end_update(context); (void) krb5_db2_unlock(context); /* unlock write lock */ return retval; }
/* Free an entry returned by krb5_db2_get_principal. */ void krb5_db2_free_principal(krb5_context context, krb5_db_entry *entry) { krb5_dbe_free(context, entry); }
krb5_error_code krb5_db2_iterate_ext(krb5_context context, krb5_error_code(*func) (krb5_pointer, krb5_db_entry *), krb5_pointer func_arg, int backwards, int recursive) { krb5_db2_context *db_ctx; DB *db; DBT key, contents; krb5_data contdata; krb5_db_entry *entry; krb5_error_code retval; int dbret; void *cookie; cookie = NULL; if (!k5db2_inited(context)) return KRB5_KDB_DBNOTINITED; db_ctx = context->dal_handle->db_context; retval = krb5_db2_lock(context, KRB5_LOCKMODE_SHARED); if (retval) return retval; db = db_ctx->db; if (recursive && db->type != DB_BTREE) { (void) krb5_db2_unlock(context); return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */ } if (!recursive) { dbret = (*db->seq) (db, &key, &contents, backwards ? R_LAST : R_FIRST); } else { #ifdef HAVE_BT_RSEQ dbret = bt_rseq(db, &key, &contents, &cookie, backwards ? R_LAST : R_FIRST); #else (void) krb5_db2_unlock(context); return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */ #endif } while (dbret == 0) { krb5_error_code retval2; contdata.data = contents.data; contdata.length = contents.size; retval = krb5_decode_princ_entry(context, &contdata, &entry); if (retval) break; retval = k5_mutex_unlock(krb5_db2_mutex); if (retval) break; retval = (*func)(func_arg, entry); krb5_dbe_free(context, entry); retval2 = k5_mutex_lock(krb5_db2_mutex); /* Note: If re-locking fails, the wrapper in db2_exp.c will still try to unlock it again. That would be a bug. Fix when integrating the locking better. */ if (retval) break; if (retval2) { retval = retval2; break; } if (!recursive) { dbret = (*db->seq) (db, &key, &contents, backwards ? R_PREV : R_NEXT); } else { #ifdef HAVE_BT_RSEQ dbret = bt_rseq(db, &key, &contents, &cookie, backwards ? R_PREV : R_NEXT); #else (void) krb5_db2_unlock(context); return KRB5_KDB_UK_RERROR; /* Not optimal, but close enough. */ #endif } } switch (dbret) { case 1: case 0: break; case -1: default: retval = errno; } (void) krb5_db2_unlock(context); return retval; }
krb5_error_code krb5_decode_princ_entry(krb5_context context, krb5_data *content, krb5_db_entry **entry_ptr) { int sizeleft, i; unsigned char * nextloc; krb5_tl_data ** tl_data; krb5_int16 i16; krb5_db_entry * entry; krb5_error_code retval; *entry_ptr = NULL; entry = k5alloc(sizeof(*entry), &retval); if (entry == NULL) return retval; /* * Reverse the encoding of encode_princ_entry. * * The first part is decoding the base type. If the base type is * bigger than the original base type then the additional fields * need to be filled in. If the base type is larger than any * known base type the additional data goes in e_data. */ /* First do the easy stuff */ nextloc = (unsigned char *)content->data; sizeleft = content->length; if ((sizeleft -= KRB5_KDB_V1_BASE_LENGTH) < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } /* Base Length */ krb5_kdb_decode_int16(nextloc, entry->len); nextloc += 2; /* Attributes */ krb5_kdb_decode_int32(nextloc, entry->attributes); nextloc += 4; /* Max Life */ krb5_kdb_decode_int32(nextloc, entry->max_life); nextloc += 4; /* Max Renewable Life */ krb5_kdb_decode_int32(nextloc, entry->max_renewable_life); nextloc += 4; /* When the client expires */ krb5_kdb_decode_int32(nextloc, entry->expiration); nextloc += 4; /* When its passwd expires */ krb5_kdb_decode_int32(nextloc, entry->pw_expiration); nextloc += 4; /* Last successful passwd */ krb5_kdb_decode_int32(nextloc, entry->last_success); nextloc += 4; /* Last failed passwd attempt */ krb5_kdb_decode_int32(nextloc, entry->last_failed); nextloc += 4; /* # of failed passwd attempt */ krb5_kdb_decode_int32(nextloc, entry->fail_auth_count); nextloc += 4; /* # tl_data strutures */ krb5_kdb_decode_int16(nextloc, entry->n_tl_data); nextloc += 2; if (entry->n_tl_data < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } /* # key_data strutures */ krb5_kdb_decode_int16(nextloc, entry->n_key_data); nextloc += 2; if (entry->n_key_data < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } /* Check for extra data */ if (entry->len > KRB5_KDB_V1_BASE_LENGTH) { entry->e_length = entry->len - KRB5_KDB_V1_BASE_LENGTH; entry->e_data = k5memdup(nextloc, entry->e_length, &retval); if (entry->e_data == NULL) goto error_out; nextloc += entry->e_length; } /* * Get the principal name for the entry * (stored as a string which gets unparsed.) */ if ((sizeleft -= 2) < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } i = 0; krb5_kdb_decode_int16(nextloc, i16); i = (int) i16; nextloc += 2; if ((retval = krb5_parse_name(context, (char *)nextloc, &(entry->princ)))) goto error_out; if (((size_t) i != (strlen((char *)nextloc) + 1)) || (sizeleft < i)) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } sizeleft -= i; nextloc += i; /* tl_data is a linked list */ tl_data = &entry->tl_data; for (i = 0; i < entry->n_tl_data; i++) { if ((sizeleft -= 4) < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } if ((*tl_data = (krb5_tl_data *) malloc(sizeof(krb5_tl_data))) == NULL) { retval = ENOMEM; goto error_out; } (*tl_data)->tl_data_next = NULL; (*tl_data)->tl_data_contents = NULL; krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_type); nextloc += 2; krb5_kdb_decode_int16(nextloc, (*tl_data)->tl_data_length); nextloc += 2; if ((sizeleft -= (*tl_data)->tl_data_length) < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } (*tl_data)->tl_data_contents = k5memdup(nextloc, (*tl_data)->tl_data_length, &retval); if ((*tl_data)->tl_data_contents == NULL) goto error_out; nextloc += (*tl_data)->tl_data_length; tl_data = &((*tl_data)->tl_data_next); } /* key_data is an array */ if (entry->n_key_data && ((entry->key_data = (krb5_key_data *) malloc(sizeof(krb5_key_data) * entry->n_key_data)) == NULL)) { retval = ENOMEM; goto error_out; } for (i = 0; i < entry->n_key_data; i++) { krb5_key_data * key_data; int j; if ((sizeleft -= 4) < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } key_data = entry->key_data + i; memset(key_data, 0, sizeof(krb5_key_data)); krb5_kdb_decode_int16(nextloc, key_data->key_data_ver); nextloc += 2; krb5_kdb_decode_int16(nextloc, key_data->key_data_kvno); nextloc += 2; /* key_data_ver determins number of elements and how to unparse them. */ if (key_data->key_data_ver <= KRB5_KDB_V1_KEY_DATA_ARRAY) { for (j = 0; j < key_data->key_data_ver; j++) { if ((sizeleft -= 4) < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } krb5_kdb_decode_int16(nextloc, key_data->key_data_type[j]); nextloc += 2; krb5_kdb_decode_int16(nextloc, key_data->key_data_length[j]); nextloc += 2; if ((sizeleft -= key_data->key_data_length[j]) < 0) { retval = KRB5_KDB_TRUNCATED_RECORD; goto error_out; } if (key_data->key_data_length[j]) { key_data->key_data_contents[j] = k5memdup(nextloc, key_data->key_data_length[j], &retval); if (key_data->key_data_contents[j] == NULL) goto error_out; nextloc += key_data->key_data_length[j]; } } } else { /* This isn't right. I'll fix it later */ abort(); } } *entry_ptr = entry; return 0; error_out: krb5_dbe_free(context, entry); return retval; }