2 * Copyright (c) 1997 - 2006 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * Copyright (c) 2011 - Howard Chu, Symas Corp.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of the Institute nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
45 typedef struct mdb_info
{
52 static krb5_error_code
53 DB_close(krb5_context context
, HDB
*db
)
55 mdb_info
*mi
= (mdb_info
*)db
->hdb_db
;
57 mdb_cursor_close(mi
->c
);
66 static krb5_error_code
67 DB_destroy(krb5_context context
, HDB
*db
)
71 ret
= hdb_clear_master_key (context
, db
);
78 static krb5_error_code
79 DB_lock(krb5_context context
, HDB
*db
, int operation
)
85 static krb5_error_code
86 DB_unlock(krb5_context context
, HDB
*db
)
88 if (db
->lock_count
> 1) {
92 heim_assert(db
->lock_count
== 1, "HDB lock/unlock sequence does not match");
98 static krb5_error_code
99 DB_seq(krb5_context context
, HDB
*db
,
100 unsigned flags
, hdb_entry_ex
*entry
, int flag
)
102 mdb_info
*mi
= db
->hdb_db
;
104 krb5_data key_data
, data
;
109 code
= mdb_cursor_get(mi
->c
, &key
, &value
, flag
);
110 if (code
== MDB_NOTFOUND
)
111 return HDB_ERR_NOENTRY
;
115 key_data
.data
= key
.mv_data
;
116 key_data
.length
= key
.mv_size
;
117 data
.data
= value
.mv_data
;
118 data
.length
= value
.mv_size
;
119 memset(entry
, 0, sizeof(*entry
));
120 if (hdb_value2entry(context
, &data
, &entry
->entry
))
121 return DB_seq(context
, db
, flags
, entry
, MDB_NEXT
);
122 if (db
->hdb_master_key_set
&& (flags
& HDB_F_DECRYPT
)) {
123 code
= hdb_unseal_keys (context
, db
, &entry
->entry
);
125 hdb_free_entry (context
, entry
);
127 if (entry
->entry
.principal
== NULL
) {
128 entry
->entry
.principal
= malloc(sizeof(*entry
->entry
.principal
));
129 if (entry
->entry
.principal
== NULL
) {
130 hdb_free_entry (context
, entry
);
131 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
134 hdb_key2principal(context
, &key_data
, entry
->entry
.principal
);
141 static krb5_error_code
142 DB_firstkey(krb5_context context
, HDB
*db
, unsigned flags
, hdb_entry_ex
*entry
)
144 mdb_info
*mi
= db
->hdb_db
;
147 /* Always start with a fresh cursor to pick up latest DB state */
149 mdb_txn_abort(mi
->t
);
151 code
= mdb_txn_begin(mi
->e
, NULL
, MDB_RDONLY
, &mi
->t
);
155 code
= mdb_cursor_open(mi
->t
, mi
->d
, &mi
->c
);
159 return DB_seq(context
, db
, flags
, entry
, MDB_FIRST
);
163 static krb5_error_code
164 DB_nextkey(krb5_context context
, HDB
*db
, unsigned flags
, hdb_entry_ex
*entry
)
166 return DB_seq(context
, db
, flags
, entry
, MDB_NEXT
);
169 static krb5_error_code
170 DB_rename(krb5_context context
, HDB
*db
, const char *new_name
)
175 if (asprintf(&old
, "%s.mdb", db
->hdb_name
) == -1)
177 if (asprintf(&new, "%s.mdb", new_name
) == -1) {
181 ret
= rename(old
, new);
188 db
->hdb_name
= strdup(new_name
);
192 static krb5_error_code
193 DB__get(krb5_context context
, HDB
*db
, krb5_data key
, krb5_data
*reply
)
195 mdb_info
*mi
= (mdb_info
*)db
->hdb_db
;
200 k
.mv_data
= key
.data
;
201 k
.mv_size
= key
.length
;
203 code
= mdb_txn_begin(mi
->e
, NULL
, MDB_RDONLY
, &txn
);
207 code
= mdb_get(txn
, mi
->d
, &k
, &v
);
209 krb5_data_copy(reply
, v
.mv_data
, v
.mv_size
);
211 if(code
== MDB_NOTFOUND
)
212 return HDB_ERR_NOENTRY
;
216 static krb5_error_code
217 DB__put(krb5_context context
, HDB
*db
, int replace
,
218 krb5_data key
, krb5_data value
)
220 mdb_info
*mi
= (mdb_info
*)db
->hdb_db
;
225 k
.mv_data
= key
.data
;
226 k
.mv_size
= key
.length
;
227 v
.mv_data
= value
.data
;
228 v
.mv_size
= value
.length
;
230 code
= mdb_txn_begin(mi
->e
, NULL
, 0, &txn
);
234 code
= mdb_put(txn
, mi
->d
, &k
, &v
, replace
? 0 : MDB_NOOVERWRITE
);
238 code
= mdb_txn_commit(txn
);
239 if(code
== MDB_KEYEXIST
)
240 return HDB_ERR_EXISTS
;
244 static krb5_error_code
245 DB__del(krb5_context context
, HDB
*db
, krb5_data key
)
247 mdb_info
*mi
= (mdb_info
*)db
->hdb_db
;
250 krb5_error_code code
;
252 k
.mv_data
= key
.data
;
253 k
.mv_size
= key
.length
;
255 code
= mdb_txn_begin(mi
->e
, NULL
, 0, &txn
);
259 code
= mdb_del(txn
, mi
->d
, &k
, NULL
);
263 code
= mdb_txn_commit(txn
);
264 if(code
== MDB_NOTFOUND
)
265 return HDB_ERR_NOENTRY
;
269 static krb5_error_code
270 DB_open(krb5_context context
, HDB
*db
, int flags
, mode_t mode
)
272 mdb_info
*mi
= (mdb_info
*)db
->hdb_db
;
276 int myflags
= MDB_NOSUBDIR
, tmp
;
278 if((flags
& O_ACCMODE
) == O_RDONLY
)
279 myflags
|= MDB_RDONLY
;
281 if (asprintf(&fn
, "%s.mdb", db
->hdb_name
) == -1) {
282 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
285 if (mdb_env_create(&mi
->e
)) {
287 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
291 tmp
= krb5_config_get_int_default(context
, NULL
, 0, "kdc",
292 "hdb-mdb-maxreaders", NULL
);
294 ret
= mdb_env_set_maxreaders(mi
->e
, tmp
);
296 krb5_set_error_message(context
, ret
, "setting maxreaders on %s: %s",
297 db
->hdb_name
, mdb_strerror(ret
));
302 tmp
= krb5_config_get_int_default(context
, NULL
, 0, "kdc",
303 "hdb-mdb-mapsize", NULL
);
307 ret
= mdb_env_set_mapsize(mi
->e
, maps
);
309 krb5_set_error_message(context
, ret
, "setting mapsize on %s: %s",
310 db
->hdb_name
, mdb_strerror(ret
));
315 ret
= mdb_env_open(mi
->e
, fn
, myflags
, mode
);
318 mdb_env_close(mi
->e
);
321 krb5_set_error_message(context
, ret
, "opening %s: %s",
322 db
->hdb_name
, mdb_strerror(ret
));
327 ret
= mdb_txn_begin(mi
->e
, NULL
, MDB_RDONLY
, &txn
);
331 ret
= mdb_open(txn
, NULL
, 0, &mi
->d
);
336 if((flags
& O_ACCMODE
) == O_RDONLY
)
337 ret
= hdb_check_db_format(context
, db
);
339 ret
= hdb_init_db(context
, db
);
340 if(ret
== HDB_ERR_NOENTRY
)
343 DB_close(context
, db
);
344 krb5_set_error_message(context
, ret
, "hdb_open: failed %s database %s",
345 (flags
& O_ACCMODE
) == O_RDONLY
?
346 "checking format of" : "initialize",
354 hdb_mdb_create(krb5_context context
, HDB
**db
,
355 const char *filename
)
357 *db
= calloc(1, sizeof(**db
));
359 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
363 (*db
)->hdb_db
= calloc(1, sizeof(mdb_info
));
364 if ((*db
)->hdb_db
== NULL
) {
367 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
370 (*db
)->hdb_name
= strdup(filename
);
371 if ((*db
)->hdb_name
== NULL
) {
375 krb5_set_error_message(context
, ENOMEM
, "malloc: out of memory");
378 (*db
)->hdb_master_key_set
= 0;
379 (*db
)->hdb_openp
= 0;
380 (*db
)->hdb_capability_flags
= HDB_CAP_F_HANDLE_ENTERPRISE_PRINCIPAL
;
381 (*db
)->hdb_open
= DB_open
;
382 (*db
)->hdb_close
= DB_close
;
383 (*db
)->hdb_fetch_kvno
= _hdb_fetch_kvno
;
384 (*db
)->hdb_store
= _hdb_store
;
385 (*db
)->hdb_remove
= _hdb_remove
;
386 (*db
)->hdb_firstkey
= DB_firstkey
;
387 (*db
)->hdb_nextkey
= DB_nextkey
;
388 (*db
)->hdb_lock
= DB_lock
;
389 (*db
)->hdb_unlock
= DB_unlock
;
390 (*db
)->hdb_rename
= DB_rename
;
391 (*db
)->hdb__get
= DB__get
;
392 (*db
)->hdb__put
= DB__put
;
393 (*db
)->hdb__del
= DB__del
;
394 (*db
)->hdb_destroy
= DB_destroy
;
397 #endif /* HAVE_MDB */