Implemented plugin facility. First use is authentication from
authorAdam Dickmeiss <adam@indexdata.dk>
Fri, 11 Feb 2005 15:19:07 +0000 (15:19 +0000)
committerAdam Dickmeiss <adam@indexdata.dk>
Fri, 11 Feb 2005 15:19:07 +0000 (15:19 +0000)
external sources.

NEWS
configure.in
etc/config.xml
include/yazproxy/Makefile.am
include/yazproxy/module.h [new file with mode: 0644]
include/yazproxy/proxy.h
src/Makefile.am
src/mod_sample.cpp [new file with mode: 0644]
src/proxyp.h
src/yaz-proxy-config.cpp
src/yaz-proxy.cpp

diff --git a/NEWS b/NEWS
index 1277a1e..196f87e 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,11 @@
-<<YAZ Proxy involved in Character Set and Language Negotiation. Added
+
+Started work on facility for module loading (plugins). Initial
+effort is to be able to authenticate via a module. See mod_sample.cpp.
+
+YAZ Proxy involved in Character Set and Language Negotiation. Added
 support for client's side negotiation record (high priority). Added
 support for new elements of YAZ Proxy config file - negotiation-charset,
-negotiation-lang for parent element target.>>
+negotiation-lang for parent element target.
  
 --- 0.9 2005/02/07
 
index ea6e2c4..4e6808b 100644 (file)
@@ -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)
index da92156..6fffe7b 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0"?>
-<!-- $Id: config.xml,v 1.7 2004-11-09 14:24:22 adam Exp $ -->
+<!-- $Id: config.xml,v 1.8 2005-02-11 15:19:07 adam Exp $ -->
 <proxy xmlns="http://indexdata.dk/yazproxy/schema/0.8/"
  xmlns:xi="http://www.w3.org/2001/XInclude"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
@@ -7,9 +7,11 @@
 >
 <!-- Config can be checked with xerces-c++: PParse -n -s config.xml -->
   <target name="localhost" default="1">
+    <negotiation-charset>iso-8859-1</negotiation-charset>
     <url>localhost:9999</url>
     <target-timeout>30</target-timeout>
     <client-timeout>60</client-timeout>
+    <authentication handler="pipe" args="authenticate.pl"/>
     <keepalive>
       <bandwidth>1000000</bandwidth>
       <pdu>1000</pdu>
@@ -29,7 +31,6 @@
     <preinit>0</preinit>
     <xi:include href="explain.xml"/>
     <cql2rpn>pqf.properties</cql2rpn>
-    <authentication>adam/x</authentication>
   </target>
   <target name="*">
     <target-timeout>60</target-timeout>
@@ -38,4 +39,5 @@
   </target>
   <max-clients>50</max-clients>
   <log>client-requests server-requests</log>
+  <module>../src/.libs/mod_proxy_sample.so</module>
 </proxy>
index f5adf36..e982516 100644 (file)
@@ -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 (file)
index 0000000..6d2fd34
--- /dev/null
@@ -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
index 120a9c4..264aac5 100644 (file)
@@ -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);
index e4502df..58e9a21 100644 (file)
@@ -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 (file)
index 0000000..05b121b
--- /dev/null
@@ -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 <string.h>
+#include <stdio.h>
+
+#include <yazproxy/module.h>
+
+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
+};
+       
index 8839106..1f2acd6 100644 (file)
@@ -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 <yazproxy/proxy.h>
+#include <yazproxy/module.h>
 
 class Yaz_usemarcon {
  public:
index fc81b94..babbd7c 100644 (file)
@@ -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 <ctype.h>
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
 #include <yaz/log.h>
 #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<Yaz_ProxyModule_int0 *>(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<Yaz_ProxyModule_int0 *>(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<Yaz_ProxyModule_int0 *>(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<Yaz_ProxyModule_entry *> 
+                   (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,
index 48460ae..4400bbb 100644 (file)
@@ -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)