| 1 | /*
 | 
|---|
| 2 |  * Copyright (c) 1997 - 2008 Kungliga Tekniska Högskolan
 | 
|---|
| 3 |  * (Royal Institute of Technology, Stockholm, Sweden).
 | 
|---|
| 4 |  * All rights reserved.
 | 
|---|
| 5 |  *
 | 
|---|
| 6 |  * Portions Copyright (c) 2009 Apple Inc. All rights reserved.
 | 
|---|
| 7 |  *
 | 
|---|
| 8 |  * Redistribution and use in source and binary forms, with or without
 | 
|---|
| 9 |  * modification, are permitted provided that the following conditions
 | 
|---|
| 10 |  * are met:
 | 
|---|
| 11 |  *
 | 
|---|
| 12 |  * 1. Redistributions of source code must retain the above copyright
 | 
|---|
| 13 |  *    notice, this list of conditions and the following disclaimer.
 | 
|---|
| 14 |  *
 | 
|---|
| 15 |  * 2. Redistributions in binary form must reproduce the above copyright
 | 
|---|
| 16 |  *    notice, this list of conditions and the following disclaimer in the
 | 
|---|
| 17 |  *    documentation and/or other materials provided with the distribution.
 | 
|---|
| 18 |  *
 | 
|---|
| 19 |  * 3. Neither the name of the Institute nor the names of its contributors
 | 
|---|
| 20 |  *    may be used to endorse or promote products derived from this software
 | 
|---|
| 21 |  *    without specific prior written permission.
 | 
|---|
| 22 |  *
 | 
|---|
| 23 |  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
 | 
|---|
| 24 |  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 | 
|---|
| 25 |  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 | 
|---|
| 26 |  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
 | 
|---|
| 27 |  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 | 
|---|
| 28 |  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 | 
|---|
| 29 |  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 | 
|---|
| 30 |  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 | 
|---|
| 31 |  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 | 
|---|
| 32 |  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 | 
|---|
| 33 |  * SUCH DAMAGE.
 | 
|---|
| 34 |  */
 | 
|---|
| 35 | 
 | 
|---|
| 36 | #include "krb5_locl.h"
 | 
|---|
| 37 | #include "hdb_locl.h"
 | 
|---|
| 38 | 
 | 
|---|
| 39 | #ifdef HAVE_DLFCN_H
 | 
|---|
| 40 | #include <dlfcn.h>
 | 
|---|
| 41 | #endif
 | 
|---|
| 42 | 
 | 
|---|
| 43 | /*! @mainpage Heimdal database backend library
 | 
|---|
| 44 |  *
 | 
|---|
| 45 |  * @section intro Introduction
 | 
|---|
| 46 |  *
 | 
|---|
| 47 |  * Heimdal libhdb library provides the backend support for Heimdal kdc
 | 
|---|
| 48 |  * and kadmind. Its here where plugins for diffrent database engines
 | 
|---|
| 49 |  * can be pluged in and extend support for here Heimdal get the
 | 
|---|
| 50 |  * principal and policy data from.
 | 
|---|
| 51 |  *
 | 
|---|
| 52 |  * Example of Heimdal backend are:
 | 
|---|
| 53 |  * - Berkeley DB 1.85
 | 
|---|
| 54 |  * - Berkeley DB 3.0
 | 
|---|
| 55 |  * - Berkeley DB 4.0
 | 
|---|
| 56 |  * - New Berkeley DB
 | 
|---|
| 57 |  * - LDAP
 | 
|---|
| 58 |  *
 | 
|---|
| 59 |  *
 | 
|---|
| 60 |  * The project web page: http://www.h5l.org/
 | 
|---|
| 61 |  *
 | 
|---|
| 62 |  */
 | 
|---|
| 63 | 
 | 
|---|
| 64 | const int hdb_interface_version = HDB_INTERFACE_VERSION;
 | 
|---|
| 65 | 
 | 
|---|
| 66 | static struct hdb_method methods[] = {
 | 
|---|
| 67 | #if HAVE_DB1 || HAVE_DB3
 | 
|---|
| 68 |     { HDB_INTERFACE_VERSION, "db:",     hdb_db_create},
 | 
|---|
| 69 | #endif
 | 
|---|
| 70 | #if HAVE_DB1
 | 
|---|
| 71 |     { HDB_INTERFACE_VERSION, "mit-db:", hdb_mdb_create},
 | 
|---|
| 72 | #endif
 | 
|---|
| 73 | #if HAVE_NDBM
 | 
|---|
| 74 |     { HDB_INTERFACE_VERSION, "ndbm:",   hdb_ndbm_create},
 | 
|---|
| 75 | #endif
 | 
|---|
| 76 |     { HDB_INTERFACE_VERSION, "keytab:", hdb_keytab_create},
 | 
|---|
| 77 | #if defined(OPENLDAP) && !defined(OPENLDAP_MODULE)
 | 
|---|
| 78 |     { HDB_INTERFACE_VERSION, "ldap:",   hdb_ldap_create},
 | 
|---|
| 79 |     { HDB_INTERFACE_VERSION, "ldapi:",  hdb_ldapi_create},
 | 
|---|
| 80 | #endif
 | 
|---|
| 81 | #ifdef HAVE_SQLITE3
 | 
|---|
| 82 |     { HDB_INTERFACE_VERSION, "sqlite:", hdb_sqlite_create},
 | 
|---|
| 83 | #endif
 | 
|---|
| 84 |     {0, NULL,   NULL}
 | 
|---|
| 85 | };
 | 
|---|
| 86 | 
 | 
|---|
| 87 | #if HAVE_DB1 || HAVE_DB3
 | 
|---|
| 88 | static struct hdb_method dbmetod =
 | 
|---|
| 89 |     { HDB_INTERFACE_VERSION, "", hdb_db_create };
 | 
|---|
| 90 | #elif defined(HAVE_NDBM)
 | 
|---|
| 91 | static struct hdb_method dbmetod =
 | 
|---|
| 92 |     { HDB_INTERFACE_VERSION, "", hdb_ndbm_create };
 | 
|---|
| 93 | #endif
 | 
|---|
| 94 | 
 | 
|---|
| 95 | 
 | 
|---|
| 96 | krb5_error_code
 | 
|---|
| 97 | hdb_next_enctype2key(krb5_context context,
 | 
|---|
| 98 |                      const hdb_entry *e,
 | 
|---|
| 99 |                      krb5_enctype enctype,
 | 
|---|
| 100 |                      Key **key)
 | 
|---|
| 101 | {
 | 
|---|
| 102 |     Key *k;
 | 
|---|
| 103 | 
 | 
|---|
| 104 |     for (k = *key ? (*key) + 1 : e->keys.val;
 | 
|---|
| 105 |          k < e->keys.val + e->keys.len;
 | 
|---|
| 106 |          k++)
 | 
|---|
| 107 |     {
 | 
|---|
| 108 |         if(k->key.keytype == enctype){
 | 
|---|
| 109 |             *key = k;
 | 
|---|
| 110 |             return 0;
 | 
|---|
| 111 |         }
 | 
|---|
| 112 |     }
 | 
|---|
| 113 |     krb5_set_error_message(context, KRB5_PROG_ETYPE_NOSUPP,
 | 
|---|
| 114 |                            "No next enctype %d for hdb-entry",
 | 
|---|
| 115 |                           (int)enctype);
 | 
|---|
| 116 |     return KRB5_PROG_ETYPE_NOSUPP; /* XXX */
 | 
|---|
| 117 | }
 | 
|---|
| 118 | 
 | 
|---|
| 119 | krb5_error_code
 | 
|---|
| 120 | hdb_enctype2key(krb5_context context,
 | 
|---|
| 121 |                 hdb_entry *e,
 | 
|---|
| 122 |                 krb5_enctype enctype,
 | 
|---|
| 123 |                 Key **key)
 | 
|---|
| 124 | {
 | 
|---|
| 125 |     *key = NULL;
 | 
|---|
| 126 |     return hdb_next_enctype2key(context, e, enctype, key);
 | 
|---|
| 127 | }
 | 
|---|
| 128 | 
 | 
|---|
| 129 | void
 | 
|---|
| 130 | hdb_free_key(Key *key)
 | 
|---|
| 131 | {
 | 
|---|
| 132 |     memset(key->key.keyvalue.data,
 | 
|---|
| 133 |            0,
 | 
|---|
| 134 |            key->key.keyvalue.length);
 | 
|---|
| 135 |     free_Key(key);
 | 
|---|
| 136 |     free(key);
 | 
|---|
| 137 | }
 | 
|---|
| 138 | 
 | 
|---|
| 139 | 
 | 
|---|
| 140 | krb5_error_code
 | 
|---|
| 141 | hdb_lock(int fd, int operation)
 | 
|---|
| 142 | {
 | 
|---|
| 143 |     int i, code = 0;
 | 
|---|
| 144 | 
 | 
|---|
| 145 |     for(i = 0; i < 3; i++){
 | 
|---|
| 146 |         code = flock(fd, (operation == HDB_RLOCK ? LOCK_SH : LOCK_EX) | LOCK_NB);
 | 
|---|
| 147 |         if(code == 0 || errno != EWOULDBLOCK)
 | 
|---|
| 148 |             break;
 | 
|---|
| 149 |         sleep(1);
 | 
|---|
| 150 |     }
 | 
|---|
| 151 |     if(code == 0)
 | 
|---|
| 152 |         return 0;
 | 
|---|
| 153 |     if(errno == EWOULDBLOCK)
 | 
|---|
| 154 |         return HDB_ERR_DB_INUSE;
 | 
|---|
| 155 |     return HDB_ERR_CANT_LOCK_DB;
 | 
|---|
| 156 | }
 | 
|---|
| 157 | 
 | 
|---|
| 158 | krb5_error_code
 | 
|---|
| 159 | hdb_unlock(int fd)
 | 
|---|
| 160 | {
 | 
|---|
| 161 |     int code;
 | 
|---|
| 162 |     code = flock(fd, LOCK_UN);
 | 
|---|
| 163 |     if(code)
 | 
|---|
| 164 |         return 4711 /* XXX */;
 | 
|---|
| 165 |     return 0;
 | 
|---|
| 166 | }
 | 
|---|
| 167 | 
 | 
|---|
| 168 | void
 | 
|---|
| 169 | hdb_free_entry(krb5_context context, hdb_entry_ex *ent)
 | 
|---|
| 170 | {
 | 
|---|
| 171 |     size_t i;
 | 
|---|
| 172 | 
 | 
|---|
| 173 |     if (ent->free_entry)
 | 
|---|
| 174 |         (*ent->free_entry)(context, ent);
 | 
|---|
| 175 | 
 | 
|---|
| 176 |     for(i = 0; i < ent->entry.keys.len; ++i) {
 | 
|---|
| 177 |         Key *k = &ent->entry.keys.val[i];
 | 
|---|
| 178 | 
 | 
|---|
| 179 |         memset (k->key.keyvalue.data, 0, k->key.keyvalue.length);
 | 
|---|
| 180 |     }
 | 
|---|
| 181 |     free_hdb_entry(&ent->entry);
 | 
|---|
| 182 | }
 | 
|---|
| 183 | 
 | 
|---|
| 184 | krb5_error_code
 | 
|---|
| 185 | hdb_foreach(krb5_context context,
 | 
|---|
| 186 |             HDB *db,
 | 
|---|
| 187 |             unsigned flags,
 | 
|---|
| 188 |             hdb_foreach_func_t func,
 | 
|---|
| 189 |             void *data)
 | 
|---|
| 190 | {
 | 
|---|
| 191 |     krb5_error_code ret;
 | 
|---|
| 192 |     hdb_entry_ex entry;
 | 
|---|
| 193 |     ret = db->hdb_firstkey(context, db, flags, &entry);
 | 
|---|
| 194 |     if (ret == 0)
 | 
|---|
| 195 |         krb5_clear_error_message(context);
 | 
|---|
| 196 |     while(ret == 0){
 | 
|---|
| 197 |         ret = (*func)(context, db, &entry, data);
 | 
|---|
| 198 |         hdb_free_entry(context, &entry);
 | 
|---|
| 199 |         if(ret == 0)
 | 
|---|
| 200 |             ret = db->hdb_nextkey(context, db, flags, &entry);
 | 
|---|
| 201 |     }
 | 
|---|
| 202 |     if(ret == HDB_ERR_NOENTRY)
 | 
|---|
| 203 |         ret = 0;
 | 
|---|
| 204 |     return ret;
 | 
|---|
| 205 | }
 | 
|---|
| 206 | 
 | 
|---|
| 207 | krb5_error_code
 | 
|---|
| 208 | hdb_check_db_format(krb5_context context, HDB *db)
 | 
|---|
| 209 | {
 | 
|---|
| 210 |     krb5_data tag;
 | 
|---|
| 211 |     krb5_data version;
 | 
|---|
| 212 |     krb5_error_code ret, ret2;
 | 
|---|
| 213 |     unsigned ver;
 | 
|---|
| 214 |     int foo;
 | 
|---|
| 215 | 
 | 
|---|
| 216 |     ret = db->hdb_lock(context, db, HDB_RLOCK);
 | 
|---|
| 217 |     if (ret)
 | 
|---|
| 218 |         return ret;
 | 
|---|
| 219 | 
 | 
|---|
| 220 |     tag.data = (void *)(intptr_t)HDB_DB_FORMAT_ENTRY;
 | 
|---|
| 221 |     tag.length = strlen(tag.data);
 | 
|---|
| 222 |     ret = (*db->hdb__get)(context, db, tag, &version);
 | 
|---|
| 223 |     ret2 = db->hdb_unlock(context, db);
 | 
|---|
| 224 |     if(ret)
 | 
|---|
| 225 |         return ret;
 | 
|---|
| 226 |     if (ret2)
 | 
|---|
| 227 |         return ret2;
 | 
|---|
| 228 |     foo = sscanf(version.data, "%u", &ver);
 | 
|---|
| 229 |     krb5_data_free (&version);
 | 
|---|
| 230 |     if (foo != 1)
 | 
|---|
| 231 |         return HDB_ERR_BADVERSION;
 | 
|---|
| 232 |     if(ver != HDB_DB_FORMAT)
 | 
|---|
| 233 |         return HDB_ERR_BADVERSION;
 | 
|---|
| 234 |     return 0;
 | 
|---|
| 235 | }
 | 
|---|
| 236 | 
 | 
|---|
| 237 | krb5_error_code
 | 
|---|
| 238 | hdb_init_db(krb5_context context, HDB *db)
 | 
|---|
| 239 | {
 | 
|---|
| 240 |     krb5_error_code ret, ret2;
 | 
|---|
| 241 |     krb5_data tag;
 | 
|---|
| 242 |     krb5_data version;
 | 
|---|
| 243 |     char ver[32];
 | 
|---|
| 244 | 
 | 
|---|
| 245 |     ret = hdb_check_db_format(context, db);
 | 
|---|
| 246 |     if(ret != HDB_ERR_NOENTRY)
 | 
|---|
| 247 |         return ret;
 | 
|---|
| 248 | 
 | 
|---|
| 249 |     ret = db->hdb_lock(context, db, HDB_WLOCK);
 | 
|---|
| 250 |     if (ret)
 | 
|---|
| 251 |         return ret;
 | 
|---|
| 252 | 
 | 
|---|
| 253 |     tag.data = (void *)(intptr_t)HDB_DB_FORMAT_ENTRY;
 | 
|---|
| 254 |     tag.length = strlen(tag.data);
 | 
|---|
| 255 |     snprintf(ver, sizeof(ver), "%u", HDB_DB_FORMAT);
 | 
|---|
| 256 |     version.data = ver;
 | 
|---|
| 257 |     version.length = strlen(version.data) + 1; /* zero terminated */
 | 
|---|
| 258 |     ret = (*db->hdb__put)(context, db, 0, tag, version);
 | 
|---|
| 259 |     ret2 = db->hdb_unlock(context, db);
 | 
|---|
| 260 |     if (ret) {
 | 
|---|
| 261 |         if (ret2)
 | 
|---|
| 262 |             krb5_clear_error_message(context);
 | 
|---|
| 263 |         return ret;
 | 
|---|
| 264 |     }
 | 
|---|
| 265 |     return ret2;
 | 
|---|
| 266 | }
 | 
|---|
| 267 | 
 | 
|---|
| 268 | #ifdef HAVE_DLOPEN
 | 
|---|
| 269 | 
 | 
|---|
| 270 |  /*
 | 
|---|
| 271 |  * Load a dynamic backend from /usr/heimdal/lib/hdb_NAME.so,
 | 
|---|
| 272 |  * looking for the hdb_NAME_create symbol.
 | 
|---|
| 273 |  */
 | 
|---|
| 274 | 
 | 
|---|
| 275 | static const struct hdb_method *
 | 
|---|
| 276 | find_dynamic_method (krb5_context context,
 | 
|---|
| 277 |                      const char *filename,
 | 
|---|
| 278 |                      const char **rest)
 | 
|---|
| 279 | {
 | 
|---|
| 280 |     static struct hdb_method method;
 | 
|---|
| 281 |     struct hdb_so_method *mso;
 | 
|---|
| 282 |     char *prefix, *path, *symbol;
 | 
|---|
| 283 |     const char *p;
 | 
|---|
| 284 |     void *dl;
 | 
|---|
| 285 |     size_t len;
 | 
|---|
| 286 | 
 | 
|---|
| 287 |     p = strchr(filename, ':');
 | 
|---|
| 288 | 
 | 
|---|
| 289 |     /* if no prefix, don't know what module to load, just ignore it */
 | 
|---|
| 290 |     if (p == NULL)
 | 
|---|
| 291 |         return NULL;
 | 
|---|
| 292 | 
 | 
|---|
| 293 |     len = p - filename;
 | 
|---|
| 294 |     *rest = filename + len + 1;
 | 
|---|
| 295 | 
 | 
|---|
| 296 |     prefix = malloc(len + 1);
 | 
|---|
| 297 |     if (prefix == NULL)
 | 
|---|
| 298 |         krb5_errx(context, 1, "out of memory");
 | 
|---|
| 299 |     strlcpy(prefix, filename, len + 1);
 | 
|---|
| 300 | 
 | 
|---|
| 301 |     if (asprintf(&path, LIBDIR "/hdb_%s.so", prefix) == -1)
 | 
|---|
| 302 |         krb5_errx(context, 1, "out of memory");
 | 
|---|
| 303 | 
 | 
|---|
| 304 | #ifndef RTLD_NOW
 | 
|---|
| 305 | #define RTLD_NOW 0
 | 
|---|
| 306 | #endif
 | 
|---|
| 307 | #ifndef RTLD_GLOBAL
 | 
|---|
| 308 | #define RTLD_GLOBAL 0
 | 
|---|
| 309 | #endif
 | 
|---|
| 310 | 
 | 
|---|
| 311 |     dl = dlopen(path, RTLD_NOW | RTLD_GLOBAL);
 | 
|---|
| 312 |     if (dl == NULL) {
 | 
|---|
| 313 |         krb5_warnx(context, "error trying to load dynamic module %s: %s\n",
 | 
|---|
| 314 |                    path, dlerror());
 | 
|---|
| 315 |         free(prefix);
 | 
|---|
| 316 |         free(path);
 | 
|---|
| 317 |         return NULL;
 | 
|---|
| 318 |     }
 | 
|---|
| 319 | 
 | 
|---|
| 320 |     if (asprintf(&symbol, "hdb_%s_interface", prefix) == -1)
 | 
|---|
| 321 |         krb5_errx(context, 1, "out of memory");
 | 
|---|
| 322 | 
 | 
|---|
| 323 |     mso = (struct hdb_so_method *) dlsym(dl, symbol);
 | 
|---|
| 324 |     if (mso == NULL) {
 | 
|---|
| 325 |         krb5_warnx(context, "error finding symbol %s in %s: %s\n",
 | 
|---|
| 326 |                    symbol, path, dlerror());
 | 
|---|
| 327 |         dlclose(dl);
 | 
|---|
| 328 |         free(symbol);
 | 
|---|
| 329 |         free(prefix);
 | 
|---|
| 330 |         free(path);
 | 
|---|
| 331 |         return NULL;
 | 
|---|
| 332 |     }
 | 
|---|
| 333 |     free(path);
 | 
|---|
| 334 |     free(symbol);
 | 
|---|
| 335 | 
 | 
|---|
| 336 |     if (mso->version != HDB_INTERFACE_VERSION) {
 | 
|---|
| 337 |         krb5_warnx(context,
 | 
|---|
| 338 |                    "error wrong version in shared module %s "
 | 
|---|
| 339 |                    "version: %d should have been %d\n",
 | 
|---|
| 340 |                    prefix, mso->version, HDB_INTERFACE_VERSION);
 | 
|---|
| 341 |         dlclose(dl);
 | 
|---|
| 342 |         free(prefix);
 | 
|---|
| 343 |         return NULL;
 | 
|---|
| 344 |     }
 | 
|---|
| 345 | 
 | 
|---|
| 346 |     if (mso->create == NULL) {
 | 
|---|
| 347 |         krb5_errx(context, 1,
 | 
|---|
| 348 |                   "no entry point function in shared mod %s ",
 | 
|---|
| 349 |                    prefix);
 | 
|---|
| 350 |         dlclose(dl);
 | 
|---|
| 351 |         free(prefix);
 | 
|---|
| 352 |         return NULL;
 | 
|---|
| 353 |     }
 | 
|---|
| 354 | 
 | 
|---|
| 355 |     method.create = mso->create;
 | 
|---|
| 356 |     method.prefix = prefix;
 | 
|---|
| 357 | 
 | 
|---|
| 358 |     return &method;
 | 
|---|
| 359 | }
 | 
|---|
| 360 | #endif /* HAVE_DLOPEN */
 | 
|---|
| 361 | 
 | 
|---|
| 362 | /*
 | 
|---|
| 363 |  * find the relevant method for `filename', returning a pointer to the
 | 
|---|
| 364 |  * rest in `rest'.
 | 
|---|
| 365 |  * return NULL if there's no such method.
 | 
|---|
| 366 |  */
 | 
|---|
| 367 | 
 | 
|---|
| 368 | static const struct hdb_method *
 | 
|---|
| 369 | find_method (const char *filename, const char **rest)
 | 
|---|
| 370 | {
 | 
|---|
| 371 |     const struct hdb_method *h;
 | 
|---|
| 372 | 
 | 
|---|
| 373 |     for (h = methods; h->prefix != NULL; ++h) {
 | 
|---|
| 374 |         if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0) {
 | 
|---|
| 375 |             *rest = filename + strlen(h->prefix);
 | 
|---|
| 376 |             return h;
 | 
|---|
| 377 |         }
 | 
|---|
| 378 |     }
 | 
|---|
| 379 | #if defined(HAVE_DB1) || defined(HAVE_DB3) || defined(HAVE_NDBM)
 | 
|---|
| 380 |     if (strncmp(filename, "/", 1) == 0
 | 
|---|
| 381 |         || strncmp(filename, "./", 2) == 0
 | 
|---|
| 382 |         || strncmp(filename, "../", 3) == 0)
 | 
|---|
| 383 |     {
 | 
|---|
| 384 |         *rest = filename;
 | 
|---|
| 385 |         return &dbmetod;
 | 
|---|
| 386 |     }
 | 
|---|
| 387 | #endif
 | 
|---|
| 388 | 
 | 
|---|
| 389 |     return NULL;
 | 
|---|
| 390 | }
 | 
|---|
| 391 | 
 | 
|---|
| 392 | krb5_error_code
 | 
|---|
| 393 | hdb_list_builtin(krb5_context context, char **list)
 | 
|---|
| 394 | {
 | 
|---|
| 395 |     const struct hdb_method *h;
 | 
|---|
| 396 |     size_t len = 0;
 | 
|---|
| 397 |     char *buf = NULL;
 | 
|---|
| 398 | 
 | 
|---|
| 399 |     for (h = methods; h->prefix != NULL; ++h) {
 | 
|---|
| 400 |         if (h->prefix[0] == '\0')
 | 
|---|
| 401 |             continue;
 | 
|---|
| 402 |         len += strlen(h->prefix) + 2;
 | 
|---|
| 403 |     }
 | 
|---|
| 404 | 
 | 
|---|
| 405 |     len += 1;
 | 
|---|
| 406 |     buf = malloc(len);
 | 
|---|
| 407 |     if (buf == NULL) {
 | 
|---|
| 408 |         krb5_set_error_message(context, ENOMEM, "malloc: out of memory");
 | 
|---|
| 409 |         return ENOMEM;
 | 
|---|
| 410 |     }
 | 
|---|
| 411 |     buf[0] = '\0';
 | 
|---|
| 412 | 
 | 
|---|
| 413 |     for (h = methods; h->prefix != NULL; ++h) {
 | 
|---|
| 414 |         if (h != methods)
 | 
|---|
| 415 |             strlcat(buf, ", ", len);
 | 
|---|
| 416 |         strlcat(buf, h->prefix, len);
 | 
|---|
| 417 |     }
 | 
|---|
| 418 |     *list = buf;
 | 
|---|
| 419 |     return 0;
 | 
|---|
| 420 | }
 | 
|---|
| 421 | 
 | 
|---|
| 422 | krb5_error_code
 | 
|---|
| 423 | _hdb_keytab2hdb_entry(krb5_context context,
 | 
|---|
| 424 |                       const krb5_keytab_entry *ktentry,
 | 
|---|
| 425 |                       hdb_entry_ex *entry)
 | 
|---|
| 426 | {
 | 
|---|
| 427 |     entry->entry.kvno = ktentry->vno;
 | 
|---|
| 428 |     entry->entry.created_by.time = ktentry->timestamp;
 | 
|---|
| 429 | 
 | 
|---|
| 430 |     entry->entry.keys.val = calloc(1, sizeof(entry->entry.keys.val[0]));
 | 
|---|
| 431 |     if (entry->entry.keys.val == NULL)
 | 
|---|
| 432 |         return ENOMEM;
 | 
|---|
| 433 |     entry->entry.keys.len = 1;
 | 
|---|
| 434 | 
 | 
|---|
| 435 |     entry->entry.keys.val[0].mkvno = NULL;
 | 
|---|
| 436 |     entry->entry.keys.val[0].salt = NULL;
 | 
|---|
| 437 | 
 | 
|---|
| 438 |     return krb5_copy_keyblock_contents(context,
 | 
|---|
| 439 |                                        &ktentry->keyblock,
 | 
|---|
| 440 |                                        &entry->entry.keys.val[0].key);
 | 
|---|
| 441 | }
 | 
|---|
| 442 | 
 | 
|---|
| 443 | /**
 | 
|---|
| 444 |  * Create a handle for a Kerberos database
 | 
|---|
| 445 |  *
 | 
|---|
| 446 |  * Create a handle for a Kerberos database backend specified by a
 | 
|---|
| 447 |  * filename.  Doesn't create a file if its doesn't exists, you have to
 | 
|---|
| 448 |  * use O_CREAT to tell the backend to create the file.
 | 
|---|
| 449 |  */
 | 
|---|
| 450 | 
 | 
|---|
| 451 | krb5_error_code
 | 
|---|
| 452 | hdb_create(krb5_context context, HDB **db, const char *filename)
 | 
|---|
| 453 | {
 | 
|---|
| 454 |     const struct hdb_method *h;
 | 
|---|
| 455 |     const char *residual;
 | 
|---|
| 456 |     krb5_error_code ret;
 | 
|---|
| 457 |     struct krb5_plugin *list = NULL, *e;
 | 
|---|
| 458 | 
 | 
|---|
| 459 |     if(filename == NULL)
 | 
|---|
| 460 |         filename = HDB_DEFAULT_DB;
 | 
|---|
| 461 |     krb5_add_et_list(context, initialize_hdb_error_table_r);
 | 
|---|
| 462 |     h = find_method (filename, &residual);
 | 
|---|
| 463 | 
 | 
|---|
| 464 |     if (h == NULL) {
 | 
|---|
| 465 |             ret = _krb5_plugin_find(context, PLUGIN_TYPE_DATA, "hdb", &list);
 | 
|---|
| 466 |             if(ret == 0 && list != NULL) {
 | 
|---|
| 467 |                     for (e = list; e != NULL; e = _krb5_plugin_get_next(e)) {
 | 
|---|
| 468 |                             h = _krb5_plugin_get_symbol(e);
 | 
|---|
| 469 |                             if (strncmp (filename, h->prefix, strlen(h->prefix)) == 0
 | 
|---|
| 470 |                                 && h->interface_version == HDB_INTERFACE_VERSION) {
 | 
|---|
| 471 |                                     residual = filename + strlen(h->prefix);
 | 
|---|
| 472 |                                     break;
 | 
|---|
| 473 |                             }
 | 
|---|
| 474 |                     }
 | 
|---|
| 475 |                     if (e == NULL) {
 | 
|---|
| 476 |                             h = NULL;
 | 
|---|
| 477 |                             _krb5_plugin_free(list);
 | 
|---|
| 478 |                     }
 | 
|---|
| 479 |             }
 | 
|---|
| 480 |     }
 | 
|---|
| 481 | 
 | 
|---|
| 482 | #ifdef HAVE_DLOPEN
 | 
|---|
| 483 |     if (h == NULL)
 | 
|---|
| 484 |         h = find_dynamic_method (context, filename, &residual);
 | 
|---|
| 485 | #endif
 | 
|---|
| 486 |     if (h == NULL)
 | 
|---|
| 487 |         krb5_errx(context, 1, "No database support for %s", filename);
 | 
|---|
| 488 |     return (*h->create)(context, db, residual);
 | 
|---|
| 489 | }
 | 
|---|