From c6ca4f0f79d5ea0ca391d420bcb6dd6b4d7935d2 Mon Sep 17 00:00:00 2001 From: Adam Dickmeiss Date: Fri, 11 Feb 2005 15:19:07 +0000 Subject: [PATCH] Implemented plugin facility. First use is authentication from external sources. --- NEWS | 8 +- configure.in | 1 + etc/config.xml | 6 +- include/yazproxy/Makefile.am | 2 +- include/yazproxy/module.h | 43 +++++++++++ include/yazproxy/proxy.h | 11 ++- src/Makefile.am | 8 +- src/mod_sample.cpp | 63 ++++++++++++++++ src/proxyp.h | 5 +- src/yaz-proxy-config.cpp | 169 +++++++++++++++++++++++++++++++++++++++--- src/yaz-proxy.cpp | 50 ++++++++++++- 11 files changed, 342 insertions(+), 24 deletions(-) create mode 100644 include/yazproxy/module.h create mode 100644 src/mod_sample.cpp diff --git a/NEWS b/NEWS index 1277a1e..196f87e 100644 --- a/NEWS +++ b/NEWS @@ -1,7 +1,11 @@ -<> +negotiation-lang for parent element target. --- 0.9 2005/02/07 diff --git a/configure.in b/configure.in index ea6e2c4..4e6808b 100644 --- a/configure.in +++ b/configure.in @@ -17,6 +17,7 @@ USEMARCON_INIT AC_CHECK_FUNCS(setrlimit getrlimit gettimeofday) AC_CHECK_HEADERS(pwd.h sys/resource.h sys/stat.h sys/time.h sys/types.h sys/wait.h unistd.h) +AC_CHECK_LIB(dl,dlopen) dnl dnl ----- libXSLT AC_SUBST(XSLT_LIBS) diff --git a/etc/config.xml b/etc/config.xml index da92156..6fffe7b 100644 --- a/etc/config.xml +++ b/etc/config.xml @@ -1,5 +1,5 @@ - + + iso-8859-1 localhost:9999 30 60 + 1000000 1000 @@ -29,7 +31,6 @@ 0 pqf.properties - adam/x 60 @@ -38,4 +39,5 @@ 50 client-requests server-requests + ../src/.libs/mod_proxy_sample.so diff --git a/include/yazproxy/Makefile.am b/include/yazproxy/Makefile.am index f5adf36..e982516 100644 --- a/include/yazproxy/Makefile.am +++ b/include/yazproxy/Makefile.am @@ -1,2 +1,2 @@ -pkginclude_HEADERS = proxy.h bw.h +pkginclude_HEADERS = proxy.h bw.h module.h diff --git a/include/yazproxy/module.h b/include/yazproxy/module.h new file mode 100644 index 0000000..6d2fd34 --- /dev/null +++ b/include/yazproxy/module.h @@ -0,0 +1,43 @@ +/* $Id: module.h,v 1.1 2005-02-11 15:19:08 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#ifndef YAZ_PROXY_MODULE_H +#define YAZ_PROXY_MODULE_H_INCLUDED + +struct Yaz_ProxyModule_entry { + int int_version; + char *module_name; + char *module_description; + void *fl; +}; + +#define YAZPROXY_RET_NOT_ME 0 /* Did not catch it. pass to other handler */ +#define YAZPROXY_RET_OK 1 /* OK, grabbed */ +#define YAZPROXY_RET_PERM 2 /* Permissiong denied, reject etc. */ + +struct Yaz_ProxyModule_int0 { + void *(*init)(void); + void (*destroy)(void *handle); + int (*authenticate)(void *handle, + const char *user, const char *group, const char *pw); +}; + +#endif diff --git a/include/yazproxy/proxy.h b/include/yazproxy/proxy.h index 120a9c4..264aac5 100644 --- a/include/yazproxy/proxy.h +++ b/include/yazproxy/proxy.h @@ -1,5 +1,5 @@ -/* $Id: proxy.h,v 1.11 2005-02-10 08:09:42 oleg Exp $ - Copyright (c) 1998-2004, Index Data. +/* $Id: proxy.h,v 1.12 2005-02-11 15:19:08 adam Exp $ + Copyright (c) 1998-2005, Index Data. This file is part of the yaz-proxy. @@ -84,8 +84,10 @@ public: Odr_oid *syntax, Z_RecordComposition *comp, char **addinfo, char **stylesheet, char **schema, char **backend_type, char **backend_charset, - char **usemarcon_ini_stage1, char **usemarcon_ini_stage2 - ); + char **usemarcon_ini_stage1, char **usemarcon_ini_stage2); + + int check_authentication(const char *user, const char *group, + const char *password); char *get_explain_doc(ODR odr, const char *name, const char *db, int *len); const char *get_explain_name(const char *db, const char **backend_db); @@ -209,6 +211,7 @@ class YAZ_EXPORT Yaz_Proxy : public Yaz_Z_Assoc { Z_GDU *m_bw_hold_PDU; int m_max_record_retrieve; void handle_max_record_retrieve(Z_APDU *apdu); + int handle_authentication(Z_APDU *apdu); void display_diagrecs(Z_DiagRec **pp, int num); Z_Records *create_nonSurrogateDiagnostics(ODR o, int error, const char *addinfo); diff --git a/src/Makefile.am b/src/Makefile.am index e4502df..58e9a21 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -## $Id: Makefile.am,v 1.4 2004-12-03 15:50:53 adam Exp $ +## $Id: Makefile.am,v 1.5 2005-02-11 15:19:08 adam Exp $ AM_CXXFLAGS = $(YAZPPINC) -I$(srcdir)/../include $(XSLT_CFLAGS) $(USEMARCONINC) @@ -18,3 +18,9 @@ cdetails_SOURCES=cdetails.cpp LDADD=libyazproxy.la $(YAZPPLALIB) $(XSLT_LIBS) $(USEMARCONLALIB) libyazproxy_la_LIBADD = $(XSLT_LIBS) + +# Modules +mod_proxy_sample_la_SOURCES = mod_sample.cpp +mod_proxy_sample_la_LDFLAGS = -rpath $(pkglibdir) -module -avoid-version + +pkglib_LTLIBRARIES = mod_proxy_sample.la diff --git a/src/mod_sample.cpp b/src/mod_sample.cpp new file mode 100644 index 0000000..05b121b --- /dev/null +++ b/src/mod_sample.cpp @@ -0,0 +1,63 @@ +/* $Id: mod_sample.cpp,v 1.1 2005-02-11 15:19:08 adam Exp $ + Copyright (c) 1998-2005, Index Data. + +This file is part of the yaz-proxy. + +YAZ proxy is free software; you can redistribute it and/or modify it under +the terms of the GNU General Public License as published by the Free +Software Foundation; either version 2, or (at your option) any later +version. + +YAZ proxy is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or +FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License +for more details. + +You should have received a copy of the GNU General Public License +along with YAZ proxy; see the file LICENSE. If not, write to the +Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA +02111-1307, USA. + */ + +#include +#include + +#include + +void *my_init(void) +{ + return 0; // no private data for handler +} + +void my_destroy(void *p) +{ + // private data destroy +} + +int my_authenticate(void *p, const char *user, const char *group, + const char *password) +{ + fprintf(stderr, "my_authenticate: user=%s group=%s\n", + user ? user : "none", group ? group : "none"); + // authentication handler + if (!user && !group && !password) + return YAZPROXY_RET_OK; // OK if anonymous + if (user && !strcmp(user, "guest") + && password && !strcmp(password, "guest")) // or guest guest + return YAZPROXY_RET_OK; + return YAZPROXY_RET_PERM; // fail otherwise +} + +Yaz_ProxyModule_int0 interface0 = { + my_init, + my_destroy, + my_authenticate +}; + +Yaz_ProxyModule_entry yazproxy_module = { + 0, // interface version + "sample", // name + "Sample Module for YAZ Proxy",// description + &interface0 +}; + diff --git a/src/proxyp.h b/src/proxyp.h index 8839106..1f2acd6 100644 --- a/src/proxyp.h +++ b/src/proxyp.h @@ -1,5 +1,5 @@ -/* $Id: proxyp.h,v 1.1 2004-12-03 14:28:18 adam Exp $ - Copyright (c) 1998-2004, Index Data. +/* $Id: proxyp.h,v 1.2 2005-02-11 15:19:08 adam Exp $ + Copyright (c) 1998-2005, Index Data. This file is part of the yaz-proxy. @@ -32,6 +32,7 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA #endif #include +#include class Yaz_usemarcon { public: diff --git a/src/yaz-proxy-config.cpp b/src/yaz-proxy-config.cpp index fc81b94..babbd7c 100644 --- a/src/yaz-proxy-config.cpp +++ b/src/yaz-proxy-config.cpp @@ -1,5 +1,5 @@ -/* $Id: yaz-proxy-config.cpp,v 1.14 2005-02-10 08:09:42 oleg Exp $ - Copyright (c) 1998-2004, Index Data. +/* $Id: yaz-proxy-config.cpp,v 1.15 2005-02-11 15:19:08 adam Exp $ + Copyright (c) 1998-2005, Index Data. This file is part of the yaz-proxy. @@ -20,18 +20,83 @@ Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA */ #include + +#if HAVE_DLFCN_H +#include +#endif + #include #include "proxyp.h" + +class Yaz_ProxyModule { +private: + void *m_dl_handle; /* dlopen/close handle */ + Yaz_ProxyModule_entry *m_entry; + Yaz_ProxyModule *m_next; + void *m_user_handle; /* user handle */ +public: + Yaz_ProxyModule(void *dl_handle, Yaz_ProxyModule_entry *ent, + Yaz_ProxyModule *next); + ~Yaz_ProxyModule(); + Yaz_ProxyModule *get_next() { return m_next; }; + int authenticate(const char *user, const char *group, const char *password); +}; + +Yaz_ProxyModule::Yaz_ProxyModule(void *dl_handle, Yaz_ProxyModule_entry *ent, + Yaz_ProxyModule *next) +{ + m_dl_handle = dl_handle; + m_entry = ent; + m_next = next; + m_user_handle = 0; + if (m_entry->int_version == 0) + { + struct Yaz_ProxyModule_int0 *int0 = + reinterpret_cast(m_entry->fl); + if (int0->init) + m_user_handle = (*int0->init)(); + } +} + +Yaz_ProxyModule::~Yaz_ProxyModule() +{ + if (m_entry->int_version == 0) + { + struct Yaz_ProxyModule_int0 *int0 = + reinterpret_cast(m_entry->fl); + if (int0->destroy) + (*int0->destroy)(m_user_handle); + } + dlclose(m_dl_handle); +} + +int Yaz_ProxyModule::authenticate(const char *user, const char *group, + const char *password) +{ + if (m_entry->int_version == 0) + { + struct Yaz_ProxyModule_int0 *int0 = + reinterpret_cast(m_entry->fl); + + if (!int0->authenticate) + return YAZPROXY_RET_NOT_ME; + return (*int0->authenticate)(m_user_handle, user, group, password); + } + return YAZPROXY_RET_NOT_ME; +} + class Yaz_ProxyConfigP { friend class Yaz_ProxyConfig; - int m_copy; + Yaz_ProxyModule *m_modules; int mycmp(const char *hay, const char *item, size_t len); int match_list(int v, const char *m); int atoi_l(const char **cp); #if HAVE_XSLT + void load_modules(void); + void unload_modules(void); int check_schema(xmlNodePtr ptr, Z_RecordComposition *comp, const char *schema_identifier); xmlDocPtr m_docPtr; @@ -59,27 +124,88 @@ class Yaz_ProxyConfigP { int get_explain_ptr(const char *host, const char *db, xmlNodePtr *ptr_target, xmlNodePtr *ptr_explain); #endif + Yaz_ProxyConfigP(); + ~Yaz_ProxyConfigP(); }; -Yaz_ProxyConfig::Yaz_ProxyConfig() +Yaz_ProxyConfigP::Yaz_ProxyConfigP() { - m_cp = new Yaz_ProxyConfigP; - m_cp->m_copy = 0; #if HAVE_XSLT - m_cp->m_docPtr = 0; - m_cp->m_proxyPtr = 0; + m_docPtr = 0; + m_proxyPtr = 0; #endif + m_modules = 0; } -Yaz_ProxyConfig::~Yaz_ProxyConfig() +Yaz_ProxyConfigP::~Yaz_ProxyConfigP() { #if HAVE_XSLT - if (!m_cp->m_copy && m_cp->m_docPtr) - xmlFreeDoc(m_cp->m_docPtr); + if (m_docPtr) + xmlFreeDoc(m_docPtr); #endif +} + +Yaz_ProxyConfig::Yaz_ProxyConfig() +{ + m_cp = new Yaz_ProxyConfigP; +} + +Yaz_ProxyConfig::~Yaz_ProxyConfig() +{ delete m_cp; } +#if HAVE_XSLT +void Yaz_ProxyConfigP::unload_modules() +{ + yaz_log(YLOG_WARN, "unload_modules not implemented yet"); +} +#endif + +#if HAVE_XSLT +void Yaz_ProxyConfigP::load_modules() +{ + if (!m_proxyPtr) + return; + xmlNodePtr ptr; + for (ptr = m_proxyPtr->children; ptr; ptr = ptr->next) + { + const char *fname; + if (ptr->type == XML_ELEMENT_NODE + && !strcmp((const char *) ptr->name, "module") + && (fname = get_text(ptr))) + { +#if HAVE_DLFCN_H + void *dl_handle = dlopen(fname, RTLD_NOW|RTLD_GLOBAL); + if (dl_handle) + { + Yaz_ProxyModule_entry *fl_ptr = 0; + fl_ptr = reinterpret_cast + (dlsym(dl_handle, "yazproxy_module")); + if (fl_ptr) + { + Yaz_ProxyModule *m = new Yaz_ProxyModule(dl_handle, + fl_ptr, + m_modules); + m_modules = m; + yaz_log(YLOG_LOG, "Loading %s OK", fname); + } + else + { + yaz_log(YLOG_WARN, "Loading %s FAIL: missing yazproxy_module symbol", fname); + dlclose(dl_handle); + } + } + else + yaz_log(YLOG_WARN, "Loading %s FAIL: dlopen failed", fname); +#else + yaz_log(YLOG_WARN, "Loading &s FAIL: dl unsupported", fname); +#endif + } + } +} +#endif + int Yaz_ProxyConfig::read_xml(const char *fname) { #if HAVE_XSLT @@ -108,6 +234,9 @@ int Yaz_ProxyConfig::read_xml(const char *fname) if (m_cp->m_docPtr) xmlFreeDoc(m_cp->m_docPtr); m_cp->m_docPtr = ndoc; + + m_cp->unload_modules(); + m_cp->load_modules(); return 0; #else return -2; @@ -501,6 +630,24 @@ const char *Yaz_ProxyConfig::check_mime_type(const char *path) } +int Yaz_ProxyConfig::check_authentication(const char *user, + const char *group, + const char *password) +{ + Yaz_ProxyModule *m = m_cp->m_modules; + + int ret = YAZPROXY_RET_NOT_ME; + for (; m; m = m->get_next()) + { + ret = m->authenticate(user, group, password); + if (ret != YAZPROXY_RET_NOT_ME) + break; + } + if (ret == YAZPROXY_RET_PERM) + return 0; + return 1; +} + int Yaz_ProxyConfig::check_syntax(ODR odr, const char *name, Odr_oid *syntax, Z_RecordComposition *comp, char **addinfo, diff --git a/src/yaz-proxy.cpp b/src/yaz-proxy.cpp index 48460ae..4400bbb 100644 --- a/src/yaz-proxy.cpp +++ b/src/yaz-proxy.cpp @@ -1,4 +1,4 @@ -/* $Id: yaz-proxy.cpp,v 1.21 2005-02-10 19:17:44 adam Exp $ +/* $Id: yaz-proxy.cpp,v 1.22 2005-02-11 15:19:08 adam Exp $ Copyright (c) 1998-2005, Index Data. This file is part of the yaz-proxy. @@ -249,6 +249,7 @@ void Yaz_Proxy::set_proxy_authentication (const char *auth) if (auth) m_proxy_authentication = (char *) xstrdup (auth); } + void Yaz_Proxy::set_proxy_negotiation (const char *charset, const char *lang) { yaz_log(YLOG_LOG, "%sSet the proxy negotiation: charset to '%s', " @@ -262,6 +263,7 @@ void Yaz_Proxy::set_proxy_negotiation (const char *charset, const char *lang) if (lang) m_proxy_negotiation_lang = (char *) xstrdup (lang); } + Yaz_ProxyConfig *Yaz_Proxy::check_reconfigure() { if (m_parent) @@ -1835,6 +1837,41 @@ Z_APDU *Yaz_Proxy::handle_query_validation(Z_APDU *apdu) return apdu; } +int Yaz_Proxy::handle_authentication(Z_APDU *apdu) +{ + if (apdu->which != Z_APDU_initRequest) + return 1; // pass if no init request + Z_InitRequest *req = apdu->u.initRequest; + + Yaz_ProxyConfig *cfg = check_reconfigure(); + if (!cfg) + return 1; // pass if no config + + int ret; + if (req->idAuthentication == 0) + { + ret = cfg->check_authentication(0, 0, 0); + } + else if (req->idAuthentication->which == Z_IdAuthentication_idPass) + { + ret = cfg->check_authentication( + req->idAuthentication->u.idPass->userId, + req->idAuthentication->u.idPass->groupId, + req->idAuthentication->u.idPass->password); + } + else if (req->idAuthentication->which == Z_IdAuthentication_open) + { + char user[64], pass[64]; + *user = '\0'; + *pass = '\0'; + sscanf(req->idAuthentication->u.open, "%63[^/]/%63s", user, pass); + ret = cfg->check_authentication(user, 0, pass); + } + else + ret = cfg->check_authentication(0, 0, 0); + return ret; +} + Z_APDU *Yaz_Proxy::handle_syntax_validation(Z_APDU *apdu) { m_marcxml_flag = 0; @@ -2562,6 +2599,17 @@ void Yaz_Proxy::handle_incoming_Z_PDU(Z_APDU *apdu) } m_client->m_init_flag = 1; } + + if (!handle_authentication(apdu)) + { + Z_APDU *apdu_reject = zget_APDU(odr_encode(), Z_APDU_initResponse); + *apdu_reject->u.initResponse->result = 0; + send_to_client(apdu_reject); + + shutdown(); + return; + } + handle_max_record_retrieve(apdu); if (apdu) -- 1.7.10.4