00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <config.h>
00020
00021 #include <stdio.h>
00022 #include <string.h>
00023 #include <stdlib.h>
00024 #include <dlfcn.h>
00025
00026 #include <dns/log.h>
00027 #include <dns/result.h>
00028 #include <dns/dlz_dlopen.h>
00029
00030 #include <isc/mem.h>
00031 #include <isc/print.h>
00032 #include <isc/result.h>
00033 #include <isc/util.h>
00034
00035 #include <named/globals.h>
00036
00037 #include <dlz/dlz_dlopen_driver.h>
00038
00039 #ifdef ISC_DLZ_DLOPEN
00040 static dns_sdlzimplementation_t *dlz_dlopen = NULL;
00041
00042
00043 typedef struct dlopen_data {
00044 isc_mem_t *mctx;
00045 char *dl_path;
00046 char *dlzname;
00047 void *dl_handle;
00048 void *dbdata;
00049 unsigned int flags;
00050 isc_mutex_t lock;
00051 int version;
00052 isc_boolean_t in_configure;
00053
00054 dlz_dlopen_version_t *dlz_version;
00055 dlz_dlopen_create_t *dlz_create;
00056 dlz_dlopen_findzonedb_t *dlz_findzonedb;
00057 dlz_dlopen_lookup_t *dlz_lookup;
00058 dlz_dlopen_authority_t *dlz_authority;
00059 dlz_dlopen_allnodes_t *dlz_allnodes;
00060 dlz_dlopen_allowzonexfr_t *dlz_allowzonexfr;
00061 dlz_dlopen_newversion_t *dlz_newversion;
00062 dlz_dlopen_closeversion_t *dlz_closeversion;
00063 dlz_dlopen_configure_t *dlz_configure;
00064 dlz_dlopen_ssumatch_t *dlz_ssumatch;
00065 dlz_dlopen_addrdataset_t *dlz_addrdataset;
00066 dlz_dlopen_subrdataset_t *dlz_subrdataset;
00067 dlz_dlopen_delrdataset_t *dlz_delrdataset;
00068 dlz_dlopen_destroy_t *dlz_destroy;
00069 } dlopen_data_t;
00070
00071
00072 #define MAYBE_LOCK(cd) \
00073 do { \
00074 if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
00075 cd->in_configure == ISC_FALSE) \
00076 LOCK(&cd->lock); \
00077 } while (0)
00078
00079 #define MAYBE_UNLOCK(cd) \
00080 do { \
00081 if ((cd->flags & DNS_SDLZFLAG_THREADSAFE) == 0 && \
00082 cd->in_configure == ISC_FALSE) \
00083 UNLOCK(&cd->lock); \
00084 } while (0)
00085
00086
00087
00088
00089 static void dlopen_log(int level, const char *fmt, ...)
00090 {
00091 va_list ap;
00092 va_start(ap, fmt);
00093 isc_log_vwrite(dns_lctx, DNS_LOGCATEGORY_DATABASE,
00094 DNS_LOGMODULE_DLZ, ISC_LOG_DEBUG(level),
00095 fmt, ap);
00096 va_end(ap);
00097 }
00098
00099
00100
00101
00102
00103 static isc_result_t
00104 dlopen_dlz_allnodes(const char *zone, void *driverarg, void *dbdata,
00105 dns_sdlzallnodes_t *allnodes)
00106 {
00107 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00108 isc_result_t result;
00109
00110
00111 UNUSED(driverarg);
00112
00113 if (cd->dlz_allnodes == NULL) {
00114 return (ISC_R_NOPERM);
00115 }
00116
00117 MAYBE_LOCK(cd);
00118 result = cd->dlz_allnodes(zone, cd->dbdata, allnodes);
00119 MAYBE_UNLOCK(cd);
00120 return (result);
00121 }
00122
00123
00124 static isc_result_t
00125 dlopen_dlz_allowzonexfr(void *driverarg, void *dbdata, const char *name,
00126 const char *client)
00127 {
00128 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00129 isc_result_t result;
00130
00131 UNUSED(driverarg);
00132
00133
00134 if (cd->dlz_allowzonexfr == NULL) {
00135 return (ISC_R_NOPERM);
00136 }
00137
00138 MAYBE_LOCK(cd);
00139 result = cd->dlz_allowzonexfr(cd->dbdata, name, client);
00140 MAYBE_UNLOCK(cd);
00141 return (result);
00142 }
00143
00144 static isc_result_t
00145 dlopen_dlz_authority(const char *zone, void *driverarg, void *dbdata,
00146 dns_sdlzlookup_t *lookup)
00147 {
00148 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00149 isc_result_t result;
00150
00151 UNUSED(driverarg);
00152
00153 if (cd->dlz_authority == NULL) {
00154 return (ISC_R_NOTIMPLEMENTED);
00155 }
00156
00157 MAYBE_LOCK(cd);
00158 result = cd->dlz_authority(zone, cd->dbdata, lookup);
00159 MAYBE_UNLOCK(cd);
00160 return (result);
00161 }
00162
00163 static isc_result_t
00164 dlopen_dlz_findzonedb(void *driverarg, void *dbdata, const char *name,
00165 dns_clientinfomethods_t *methods,
00166 dns_clientinfo_t *clientinfo)
00167 {
00168 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00169 isc_result_t result;
00170
00171 UNUSED(driverarg);
00172
00173 MAYBE_LOCK(cd);
00174 result = cd->dlz_findzonedb(cd->dbdata, name, methods, clientinfo);
00175 MAYBE_UNLOCK(cd);
00176 return (result);
00177 }
00178
00179
00180 static isc_result_t
00181 dlopen_dlz_lookup(const char *zone, const char *name, void *driverarg,
00182 void *dbdata, dns_sdlzlookup_t *lookup,
00183 dns_clientinfomethods_t *methods,
00184 dns_clientinfo_t *clientinfo)
00185 {
00186 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00187 isc_result_t result;
00188
00189 UNUSED(driverarg);
00190
00191 MAYBE_LOCK(cd);
00192 result = cd->dlz_lookup(zone, name, cd->dbdata, lookup,
00193 methods, clientinfo);
00194 MAYBE_UNLOCK(cd);
00195 return (result);
00196 }
00197
00198
00199
00200
00201 static void *
00202 dl_load_symbol(dlopen_data_t *cd, const char *symbol, isc_boolean_t mandatory) {
00203 void *ptr = dlsym(cd->dl_handle, symbol);
00204 if (ptr == NULL && mandatory) {
00205 dlopen_log(ISC_LOG_ERROR,
00206 "dlz_dlopen: library '%s' is missing "
00207 "required symbol '%s'", cd->dl_path, symbol);
00208 }
00209 return (ptr);
00210 }
00211
00212
00213
00214
00215 static isc_result_t
00216 dlopen_dlz_create(const char *dlzname, unsigned int argc, char *argv[],
00217 void *driverarg, void **dbdata)
00218 {
00219 dlopen_data_t *cd;
00220 isc_mem_t *mctx = NULL;
00221 isc_result_t result = ISC_R_FAILURE;
00222 int dlopen_flags = 0;
00223
00224 UNUSED(driverarg);
00225
00226 if (argc < 2) {
00227 dlopen_log(ISC_LOG_ERROR,
00228 "dlz_dlopen driver for '%s' needs a path to "
00229 "the shared library", dlzname);
00230 return (ISC_R_FAILURE);
00231 }
00232
00233 result = isc_mem_create(0, 0, &mctx);
00234 if (result != ISC_R_SUCCESS)
00235 return (result);
00236
00237 cd = isc_mem_get(mctx, sizeof(*cd));
00238 if (cd == NULL) {
00239 isc_mem_destroy(&mctx);
00240 return (ISC_R_NOMEMORY);
00241 }
00242 memset(cd, 0, sizeof(*cd));
00243
00244 cd->mctx = mctx;
00245
00246 cd->dl_path = isc_mem_strdup(cd->mctx, argv[1]);
00247 if (cd->dl_path == NULL) {
00248 result = ISC_R_NOMEMORY;
00249 goto failed;
00250 }
00251
00252 cd->dlzname = isc_mem_strdup(cd->mctx, dlzname);
00253 if (cd->dlzname == NULL) {
00254 result = ISC_R_NOMEMORY;
00255 goto failed;
00256 }
00257
00258
00259 result = isc_mutex_init(&cd->lock);
00260 if (result != ISC_R_SUCCESS)
00261 goto failed;
00262
00263
00264 dlopen_flags = RTLD_NOW|RTLD_GLOBAL;
00265
00266 #ifdef RTLD_DEEPBIND
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 dlopen_flags |= RTLD_DEEPBIND;
00277 #endif
00278
00279 cd->dl_handle = dlopen(cd->dl_path, dlopen_flags);
00280 if (cd->dl_handle == NULL) {
00281 dlopen_log(ISC_LOG_ERROR,
00282 "dlz_dlopen failed to open library '%s' - %s",
00283 cd->dl_path, dlerror());
00284 result = ISC_R_FAILURE;
00285 goto failed;
00286 }
00287
00288
00289 cd->dlz_version = (dlz_dlopen_version_t *)
00290 dl_load_symbol(cd, "dlz_version", ISC_TRUE);
00291 cd->dlz_create = (dlz_dlopen_create_t *)
00292 dl_load_symbol(cd, "dlz_create", ISC_TRUE);
00293 cd->dlz_lookup = (dlz_dlopen_lookup_t *)
00294 dl_load_symbol(cd, "dlz_lookup", ISC_TRUE);
00295 cd->dlz_findzonedb = (dlz_dlopen_findzonedb_t *)
00296 dl_load_symbol(cd, "dlz_findzonedb", ISC_TRUE);
00297
00298 if (cd->dlz_create == NULL ||
00299 cd->dlz_version == NULL ||
00300 cd->dlz_lookup == NULL ||
00301 cd->dlz_findzonedb == NULL)
00302 {
00303
00304 result = ISC_R_FAILURE;
00305 goto failed;
00306 }
00307
00308 cd->dlz_allowzonexfr = (dlz_dlopen_allowzonexfr_t *)
00309 dl_load_symbol(cd, "dlz_allowzonexfr", ISC_FALSE);
00310 cd->dlz_allnodes = (dlz_dlopen_allnodes_t *)
00311 dl_load_symbol(cd, "dlz_allnodes",
00312 ISC_TF(cd->dlz_allowzonexfr != NULL));
00313 cd->dlz_authority = (dlz_dlopen_authority_t *)
00314 dl_load_symbol(cd, "dlz_authority", ISC_FALSE);
00315 cd->dlz_newversion = (dlz_dlopen_newversion_t *)
00316 dl_load_symbol(cd, "dlz_newversion", ISC_FALSE);
00317 cd->dlz_closeversion = (dlz_dlopen_closeversion_t *)
00318 dl_load_symbol(cd, "dlz_closeversion",
00319 ISC_TF(cd->dlz_newversion != NULL));
00320 cd->dlz_configure = (dlz_dlopen_configure_t *)
00321 dl_load_symbol(cd, "dlz_configure", ISC_FALSE);
00322 cd->dlz_ssumatch = (dlz_dlopen_ssumatch_t *)
00323 dl_load_symbol(cd, "dlz_ssumatch", ISC_FALSE);
00324 cd->dlz_addrdataset = (dlz_dlopen_addrdataset_t *)
00325 dl_load_symbol(cd, "dlz_addrdataset", ISC_FALSE);
00326 cd->dlz_subrdataset = (dlz_dlopen_subrdataset_t *)
00327 dl_load_symbol(cd, "dlz_subrdataset", ISC_FALSE);
00328 cd->dlz_delrdataset = (dlz_dlopen_delrdataset_t *)
00329 dl_load_symbol(cd, "dlz_delrdataset", ISC_FALSE);
00330 cd->dlz_destroy = (dlz_dlopen_destroy_t *)
00331 dl_load_symbol(cd, "dlz_destroy", ISC_FALSE);
00332
00333
00334 cd->version = cd->dlz_version(&cd->flags);
00335 if (cd->version < (DLZ_DLOPEN_VERSION - DLZ_DLOPEN_AGE) ||
00336 cd->version > DLZ_DLOPEN_VERSION)
00337 {
00338 dlopen_log(ISC_LOG_ERROR,
00339 "dlz_dlopen: %s: incorrect driver API version %d, "
00340 "requires %d",
00341 cd->dl_path, cd->version, DLZ_DLOPEN_VERSION);
00342 result = ISC_R_FAILURE;
00343 goto failed;
00344 }
00345
00346
00347
00348
00349
00350
00351
00352
00353 MAYBE_LOCK(cd);
00354 result = cd->dlz_create(dlzname, argc-1, argv+1,
00355 &cd->dbdata,
00356 "log", dlopen_log,
00357 "putrr", dns_sdlz_putrr,
00358 "putnamedrr", dns_sdlz_putnamedrr,
00359 "writeable_zone", dns_dlz_writeablezone,
00360 NULL);
00361 MAYBE_UNLOCK(cd);
00362 if (result != ISC_R_SUCCESS)
00363 goto failed;
00364
00365 *dbdata = cd;
00366
00367 return (ISC_R_SUCCESS);
00368
00369 failed:
00370 dlopen_log(ISC_LOG_ERROR, "dlz_dlopen of '%s' failed", dlzname);
00371 if (cd->dl_path != NULL)
00372 isc_mem_free(mctx, cd->dl_path);
00373 if (cd->dlzname != NULL)
00374 isc_mem_free(mctx, cd->dlzname);
00375 if (dlopen_flags != 0)
00376 (void) isc_mutex_destroy(&cd->lock);
00377 #ifdef HAVE_DLCLOSE
00378 if (cd->dl_handle)
00379 dlclose(cd->dl_handle);
00380 #endif
00381 isc_mem_put(mctx, cd, sizeof(*cd));
00382 isc_mem_destroy(&mctx);
00383 return (result);
00384 }
00385
00386
00387
00388
00389 static void
00390 dlopen_dlz_destroy(void *driverarg, void *dbdata) {
00391 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00392 isc_mem_t *mctx;
00393
00394 UNUSED(driverarg);
00395
00396 if (cd->dlz_destroy) {
00397 MAYBE_LOCK(cd);
00398 cd->dlz_destroy(cd->dbdata);
00399 MAYBE_UNLOCK(cd);
00400 }
00401
00402 if (cd->dl_path)
00403 isc_mem_free(cd->mctx, cd->dl_path);
00404 if (cd->dlzname)
00405 isc_mem_free(cd->mctx, cd->dlzname);
00406
00407 #ifdef HAVE_DLCLOSE
00408 if (cd->dl_handle)
00409 dlclose(cd->dl_handle);
00410 #endif
00411
00412 (void) isc_mutex_destroy(&cd->lock);
00413
00414 mctx = cd->mctx;
00415 isc_mem_put(mctx, cd, sizeof(*cd));
00416 isc_mem_destroy(&mctx);
00417 }
00418
00419
00420
00421
00422 static isc_result_t
00423 dlopen_dlz_newversion(const char *zone, void *driverarg, void *dbdata,
00424 void **versionp)
00425 {
00426 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00427 isc_result_t result;
00428
00429 UNUSED(driverarg);
00430
00431 if (cd->dlz_newversion == NULL)
00432 return (ISC_R_NOTIMPLEMENTED);
00433
00434 MAYBE_LOCK(cd);
00435 result = cd->dlz_newversion(zone, cd->dbdata, versionp);
00436 MAYBE_UNLOCK(cd);
00437 return (result);
00438 }
00439
00440
00441
00442
00443 static void
00444 dlopen_dlz_closeversion(const char *zone, isc_boolean_t commit,
00445 void *driverarg, void *dbdata, void **versionp)
00446 {
00447 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00448
00449 UNUSED(driverarg);
00450
00451 if (cd->dlz_newversion == NULL) {
00452 *versionp = NULL;
00453 return;
00454 }
00455
00456 MAYBE_LOCK(cd);
00457 cd->dlz_closeversion(zone, commit, cd->dbdata, versionp);
00458 MAYBE_UNLOCK(cd);
00459 }
00460
00461
00462
00463
00464 static isc_result_t
00465 dlopen_dlz_configure(dns_view_t *view, dns_dlzdb_t *dlzdb,
00466 void *driverarg, void *dbdata)
00467 {
00468 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00469 isc_result_t result;
00470
00471 UNUSED(driverarg);
00472
00473 if (cd->dlz_configure == NULL)
00474 return (ISC_R_SUCCESS);
00475
00476 MAYBE_LOCK(cd);
00477 cd->in_configure = ISC_TRUE;
00478 result = cd->dlz_configure(view, dlzdb, cd->dbdata);
00479 cd->in_configure = ISC_FALSE;
00480 MAYBE_UNLOCK(cd);
00481
00482 return (result);
00483 }
00484
00485
00486
00487
00488
00489 static isc_boolean_t
00490 dlopen_dlz_ssumatch(const char *signer, const char *name, const char *tcpaddr,
00491 const char *type, const char *key, isc_uint32_t keydatalen,
00492 unsigned char *keydata, void *driverarg, void *dbdata)
00493 {
00494 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00495 isc_boolean_t ret;
00496
00497 UNUSED(driverarg);
00498
00499 if (cd->dlz_ssumatch == NULL)
00500 return (ISC_FALSE);
00501
00502 MAYBE_LOCK(cd);
00503 ret = cd->dlz_ssumatch(signer, name, tcpaddr, type, key, keydatalen,
00504 keydata, cd->dbdata);
00505 MAYBE_UNLOCK(cd);
00506
00507 return (ret);
00508 }
00509
00510
00511
00512
00513
00514 static isc_result_t
00515 dlopen_dlz_addrdataset(const char *name, const char *rdatastr,
00516 void *driverarg, void *dbdata, void *version)
00517 {
00518 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00519 isc_result_t result;
00520
00521 UNUSED(driverarg);
00522
00523 if (cd->dlz_addrdataset == NULL)
00524 return (ISC_R_NOTIMPLEMENTED);
00525
00526 MAYBE_LOCK(cd);
00527 result = cd->dlz_addrdataset(name, rdatastr, cd->dbdata, version);
00528 MAYBE_UNLOCK(cd);
00529
00530 return (result);
00531 }
00532
00533
00534
00535
00536 static isc_result_t
00537 dlopen_dlz_subrdataset(const char *name, const char *rdatastr,
00538 void *driverarg, void *dbdata, void *version)
00539 {
00540 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00541 isc_result_t result;
00542
00543 UNUSED(driverarg);
00544
00545 if (cd->dlz_subrdataset == NULL)
00546 return (ISC_R_NOTIMPLEMENTED);
00547
00548 MAYBE_LOCK(cd);
00549 result = cd->dlz_subrdataset(name, rdatastr, cd->dbdata, version);
00550 MAYBE_UNLOCK(cd);
00551
00552 return (result);
00553 }
00554
00555
00556
00557
00558 static isc_result_t
00559 dlopen_dlz_delrdataset(const char *name, const char *type,
00560 void *driverarg, void *dbdata, void *version)
00561 {
00562 dlopen_data_t *cd = (dlopen_data_t *) dbdata;
00563 isc_result_t result;
00564
00565 UNUSED(driverarg);
00566
00567 if (cd->dlz_delrdataset == NULL)
00568 return (ISC_R_NOTIMPLEMENTED);
00569
00570 MAYBE_LOCK(cd);
00571 result = cd->dlz_delrdataset(name, type, cd->dbdata, version);
00572 MAYBE_UNLOCK(cd);
00573
00574 return (result);
00575 }
00576
00577
00578 static dns_sdlzmethods_t dlz_dlopen_methods = {
00579 dlopen_dlz_create,
00580 dlopen_dlz_destroy,
00581 dlopen_dlz_findzonedb,
00582 dlopen_dlz_lookup,
00583 dlopen_dlz_authority,
00584 dlopen_dlz_allnodes,
00585 dlopen_dlz_allowzonexfr,
00586 dlopen_dlz_newversion,
00587 dlopen_dlz_closeversion,
00588 dlopen_dlz_configure,
00589 dlopen_dlz_ssumatch,
00590 dlopen_dlz_addrdataset,
00591 dlopen_dlz_subrdataset,
00592 dlopen_dlz_delrdataset
00593 };
00594 #endif
00595
00596
00597
00598
00599 isc_result_t
00600 dlz_dlopen_init(isc_mem_t *mctx) {
00601 #ifndef ISC_DLZ_DLOPEN
00602 UNUSED(mctx);
00603 return (ISC_R_NOTIMPLEMENTED);
00604 #else
00605 isc_result_t result;
00606
00607 dlopen_log(2, "Registering DLZ_dlopen driver");
00608
00609 result = dns_sdlzregister("dlopen", &dlz_dlopen_methods, NULL,
00610 DNS_SDLZFLAG_RELATIVEOWNER |
00611 DNS_SDLZFLAG_RELATIVERDATA |
00612 DNS_SDLZFLAG_THREADSAFE,
00613 mctx, &dlz_dlopen);
00614
00615 if (result != ISC_R_SUCCESS) {
00616 UNEXPECTED_ERROR(__FILE__, __LINE__,
00617 "dns_sdlzregister() failed: %s",
00618 isc_result_totext(result));
00619 result = ISC_R_UNEXPECTED;
00620 }
00621
00622 return (result);
00623 #endif
00624 }
00625
00626
00627
00628
00629
00630 void
00631 dlz_dlopen_clear(void) {
00632 #ifdef ISC_DLZ_DLOPEN
00633 dlopen_log(2, "Unregistering DLZ_dlopen driver");
00634 if (dlz_dlopen != NULL)
00635 dns_sdlzunregister(&dlz_dlopen);
00636 #endif
00637 }