From a8d7f7325952bafe7ba2a6624f5c482ff9c5f4b2 Mon Sep 17 00:00:00 2001 From: cvs2svn Date: Mon, 4 Apr 2005 23:47:33 +0000 Subject: [PATCH] This commit was manufactured by cvs2svn to create tag 'GLITE_RELEASE_1_0'. MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Sprout from master 2004-12-10 13:29:03 UTC Aleš Křenek 'added missing IS.wsdl' Cherrypick from master 2005-03-22 10:03:45 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.deployment.lb/CHANGELOG org.glite.deployment.lb/build.xml org.glite.deployment.lb/config/templates/glite-lb.cfg.xml org.glite.deployment.lb/project/build.number org.glite.deployment.lb/project/glite-lb.spec org.glite.deployment.lb/project/version.properties Cherrypick from glite-lb-client-interface_branch_1_0_0 2005-04-03 04:43:42 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.lb.client-interface/Makefile org.glite.lb.client-interface/build.xml org.glite.lb.client-interface/interface/CountRef.h org.glite.lb.client-interface/interface/Event.h.T org.glite.lb.client-interface/interface/Job.h org.glite.lb.client-interface/interface/JobStatus.h.T org.glite.lb.client-interface/interface/LoggingExceptions.h org.glite.lb.client-interface/interface/Notification.h org.glite.lb.client-interface/interface/ServerConnection.h org.glite.lb.client-interface/interface/consumer.h org.glite.lb.client-interface/interface/context.h org.glite.lb.client-interface/interface/events.h.T org.glite.lb.client-interface/interface/jobstat.h.T org.glite.lb.client-interface/interface/notification.h org.glite.lb.client-interface/interface/notifid.h org.glite.lb.client-interface/interface/producer.h.T org.glite.lb.client-interface/interface/statistics.h org.glite.lb.client-interface/project/build.number org.glite.lb.client-interface/project/configure.properties.xml org.glite.lb.client-interface/project/version.properties Cherrypick from glite-lb-client_branch_1_0_0 2005-04-03 04:49:46 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.lb.client/Makefile org.glite.lb.client/build.xml org.glite.lb.client/doc/README-acl org.glite.lb.client/doc/README-fake org.glite.lb.client/doc/README-notify org.glite.lb.client/examples/abort_job.c org.glite.lb.client/examples/change_acl.c org.glite.lb.client/examples/job_log_fake.cpp org.glite.lb.client/examples/job_status.c org.glite.lb.client/examples/producer_fake.c org.glite.lb.client/project/build.number org.glite.lb.client/project/version.properties org.glite.lb.client/src/ServerConnection.cpp org.glite.lb.client/src/logevent.c.T org.glite.lb.client/src/producer.c org.glite.lb.client/src/uiwrap.c.T Cherrypick from glite-security-proxyrenewal_branch_1_0_0_RC1 2005-03-24 11:13:57 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.security.proxyrenewal/Makefile org.glite.security.proxyrenewal/build.xml org.glite.security.proxyrenewal/config/startup org.glite.security.proxyrenewal/project/build.number org.glite.security.proxyrenewal/project/version.properties org.glite.security.proxyrenewal/src/acstack.h org.glite.security.proxyrenewal/src/commands.c org.glite.security.proxyrenewal/src/newformat.h org.glite.security.proxyrenewal/src/renew.c org.glite.security.proxyrenewal/src/renewal_locl.h org.glite.security.proxyrenewal/src/renewd.c org.glite.security.proxyrenewal/src/renewd_locl.h org.glite.security.proxyrenewal/src/voms.c Cherrypick from glite-lb-common_branch_1_1_0 2005-04-03 04:47:22 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.lb.common/Makefile org.glite.lb.common/build.xml org.glite.lb.common/interface/lb_gss.h org.glite.lb.common/project/build.number org.glite.lb.common/project/version.properties org.glite.lb.common/src/events.c.T org.glite.lb.common/src/il_log.c org.glite.lb.common/src/lb_gss.c Cherrypick from glite-lb-logger_branch_1_0_0 2005-04-03 04:55:07 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.lb.logger/build.xml org.glite.lb.logger/project/build.number org.glite.lb.logger/project/version.properties org.glite.lb.logger/src/event_queue.c org.glite.lb.logger/src/event_store.c org.glite.lb.logger/src/il_master.c org.glite.lb.logger/src/interlogd.h org.glite.lb.logger/src/queue_thread.c Cherrypick from glite-jp-primary_branch_1_0_0 2005-03-11 09:07:07 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.jp.primary/Makefile org.glite.jp.primary/build.xml org.glite.jp.primary/config/startup org.glite.jp.primary/doc/USAGE org.glite.jp.primary/doc/jpnode_install.txt org.glite.jp.primary/project/build.number org.glite.jp.primary/project/version.properties Cherrypick from glite-deployment-lb_branch_1_2_2 2005-04-04 23:47:32 UTC Alberto Di Meglio 'Release 1.2.2': org.glite.deployment.lb/config/scripts/glite-lb-config.py org.glite.deployment.lb/doc/release_notes/release_notes.doc org.glite.deployment.lb/doc/release_notes/release_notes.html org.glite.deployment.lb/doc/release_notes/release_notes.pdf org.glite.deployment.lb/project/glite-lb.sdf.xml.template org.glite.deployment.lb/project/lxscript-rpm.xsl Cherrypick from glite-lb-ws-interface_branch_1_0_0 2005-04-03 16:29:31 UTC Alberto Di Meglio 'Increased revision number': org.glite.lb.ws-interface/Makefile org.glite.lb.ws-interface/build.xml org.glite.lb.ws-interface/project/build.number org.glite.lb.ws-interface/project/version.properties org.glite.lb.ws-interface/src/LB.xml.T org.glite.lb.ws-interface/src/puke-ug.xsl Cherrypick from glite-lb_branch_1_0_0_RC1 2005-04-03 16:57:43 UTC Alberto Di Meglio 'Increased revision number': org.glite.lb/build.xml org.glite.lb/project/build.number org.glite.lb/project/dependencies.properties org.glite.lb/project/events.T org.glite.lb/project/types.T org.glite.lb/project/version.properties Cherrypick from glite-wms-utils-exception_branch_1_0_0 2005-04-04 00:48:20 UTC Alberto Di Meglio 'Increased revision number': org.glite.wms-utils.exception/build.xml org.glite.wms-utils.exception/configure.ac org.glite.wms-utils.exception/interface/glite/wmsutils/exception/Exception.h org.glite.wms-utils.exception/project/build.number org.glite.wms-utils.exception/project/version.properties org.glite.wms-utils.exception/src/Exception.cpp Cherrypick from glite-jp_branch_1_0_0_RC1 2005-03-11 09:10:32 UTC Master Builder 'Tagged dependencies properties file [GLBUILDER]': org.glite.jp/build.xml org.glite.jp/project/build.number org.glite.jp/project/dependencies.properties org.glite.jp/project/version.properties Cherrypick from glite-lb-server_branch_1_0_0 2005-04-03 04:57:12 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.lb.server/Makefile org.glite.lb.server/build.xml org.glite.lb.server/project/build.number org.glite.lb.server/project/version.properties Cherrypick from glite-jp-common_branch_1_0_0 2005-03-11 09:05:09 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.jp.common/build.xml org.glite.jp.common/project/build.number org.glite.jp.common/project/version.properties Cherrypick from glite-jp-ws-interface_branch_1_0_0 2005-03-11 09:03:28 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.jp.ws-interface/build.xml org.glite.jp.ws-interface/project/build.number org.glite.jp.ws-interface/project/version.properties Cherrypick from glite-lb-server-bones_branch_1_0_0 2005-04-03 04:53:22 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.lb.server-bones/build.xml org.glite.lb.server-bones/project/build.number org.glite.lb.server-bones/project/version.properties Cherrypick from glite-wms-utils-jobid_branch_1_0_0 2005-04-03 01:12:39 UTC Master Builder 'Incremented build number [GLBUILDER]': org.glite.wms-utils.jobid/build.xml org.glite.wms-utils.jobid/project/build.number org.glite.wms-utils.jobid/project/version.properties Delete: org.glite.jp.index/.cvsignore org.glite.jp.index/Makefile org.glite.jp.index/build.xml org.glite.jp.index/project/JobProvenanceIS.wsdl org.glite.jp.index/project/build.properties org.glite.jp.index/project/configure.properties.xml org.glite.jp.index/project/properties.xml org.glite.jp.index/project/tar_exclude org.glite.jp.index/project/version.properties org.glite.jp.index/src/simple_server.c org.glite.jp.index/src/soap_ops.c org.glite.jp.index/src/typemap.dat org.glite.lb.client/examples/log_usertag_proxy.c org.gridsite.core/.cvsignore org.gridsite.core/CHANGES org.gridsite.core/INSTALL org.gridsite.core/LICENSE org.gridsite.core/README org.gridsite.core/VERSION org.gridsite.core/build.xml org.gridsite.core/doc/README.htcp-bin org.gridsite.core/doc/admin.html org.gridsite.core/doc/build-apache2.sh org.gridsite.core/doc/config.html org.gridsite.core/doc/findproxyfile.1 org.gridsite.core/doc/gacl.html org.gridsite.core/doc/htcp.1 org.gridsite.core/doc/htll.1 org.gridsite.core/doc/htls.1 org.gridsite.core/doc/htmkdir.1 org.gridsite.core/doc/htrm.1 org.gridsite.core/doc/httpd-fileserver.conf org.gridsite.core/doc/httpd-webserver.conf org.gridsite.core/doc/index.html org.gridsite.core/doc/install.html org.gridsite.core/doc/library.html org.gridsite.core/doc/module.html org.gridsite.core/doc/urlencode.1 org.gridsite.core/doc/user.html org.gridsite.core/interface/gridsite-gacl.h org.gridsite.core/interface/gridsite.h org.gridsite.core/project/build.properties org.gridsite.core/project/configure.properties.xml org.gridsite.core/project/dependencies.properties org.gridsite.core/project/gridsite.core.csf.xml org.gridsite.core/project/properties.xml org.gridsite.core/project/taskdefs.xml org.gridsite.core/project/version.properties org.gridsite.core/src/Doxyfile org.gridsite.core/src/Makefile org.gridsite.core/src/delegation.h org.gridsite.core/src/doxygen.css org.gridsite.core/src/doxyheader.html org.gridsite.core/src/findproxyfile.c org.gridsite.core/src/gaclexample.c org.gridsite.core/src/gridsite.spec org.gridsite.core/src/grst-delegation.c org.gridsite.core/src/grst_admin.h org.gridsite.core/src/grst_admin_file.c org.gridsite.core/src/grst_admin_gacl.c org.gridsite.core/src/grst_admin_main.c org.gridsite.core/src/grst_gacl.c org.gridsite.core/src/grst_http.c org.gridsite.core/src/grst_x509.c org.gridsite.core/src/htcp org.gridsite.core/src/htcp.c org.gridsite.core/src/htproxyput.c org.gridsite.core/src/mod_gridsite.c org.gridsite.core/src/mod_ssl-private.h org.gridsite.core/src/proxyput-example.c org.gridsite.core/src/real-gridsite-admin.cgi org.gridsite.core/src/roffit org.gridsite.core/src/urlencode.c --- org.glite.deployment.lb/CHANGELOG | 20 + org.glite.deployment.lb/build.xml | 6 + .../config/scripts/glite-lb-config.py | 306 ++- .../config/templates/glite-lb.cfg.xml | 132 +- .../doc/release_notes/release_notes.doc | Bin 172032 -> 334848 bytes .../doc/release_notes/release_notes.html | 2392 +++++++++++++++++--- .../doc/release_notes/release_notes.pdf | Bin 34870 -> 277829 bytes org.glite.deployment.lb/project/build.number | 2 + .../project/glite-lb.sdf.xml.template | 85 +- org.glite.deployment.lb/project/glite-lb.spec | 2 +- org.glite.deployment.lb/project/lxscript-rpm.xsl | 94 +- org.glite.deployment.lb/project/version.properties | 8 +- org.glite.jp.common/build.xml | 5 + org.glite.jp.common/project/build.number | 2 + org.glite.jp.common/project/version.properties | 8 +- org.glite.jp.index/.cvsignore | 1 - org.glite.jp.index/Makefile | 129 -- org.glite.jp.index/build.xml | 93 - org.glite.jp.index/project/JobProvenanceIS.wsdl | 531 ----- org.glite.jp.index/project/build.properties | 0 .../project/configure.properties.xml | 53 - org.glite.jp.index/project/properties.xml | 52 - org.glite.jp.index/project/tar_exclude | 10 - org.glite.jp.index/project/version.properties | 4 - org.glite.jp.index/src/simple_server.c | 39 - org.glite.jp.index/src/soap_ops.c | 81 - org.glite.jp.index/src/typemap.dat | 2 - org.glite.jp.primary/Makefile | 5 +- org.glite.jp.primary/build.xml | 6 + org.glite.jp.primary/config/startup | 90 + org.glite.jp.primary/doc/USAGE | 100 + org.glite.jp.primary/doc/jpnode_install.txt | 72 + org.glite.jp.primary/project/build.number | 2 + org.glite.jp.primary/project/version.properties | 8 +- org.glite.jp.ws-interface/build.xml | 4 + org.glite.jp.ws-interface/project/build.number | 2 + .../project/version.properties | 7 +- org.glite.jp/build.xml | 9 +- org.glite.jp/project/build.number | 2 + org.glite.jp/project/dependencies.properties | 19 +- org.glite.jp/project/version.properties | 8 +- org.glite.lb.client-interface/Makefile | 3 +- org.glite.lb.client-interface/build.xml | 4 + org.glite.lb.client-interface/interface/CountRef.h | 42 +- org.glite.lb.client-interface/interface/Event.h.T | 153 +- org.glite.lb.client-interface/interface/Job.h | 198 +- .../interface/JobStatus.h.T | 216 +- .../interface/LoggingExceptions.h | 138 +- .../interface/Notification.h | 29 +- .../interface/ServerConnection.h | 677 +++++- org.glite.lb.client-interface/interface/consumer.h | 209 +- org.glite.lb.client-interface/interface/context.h | 66 +- org.glite.lb.client-interface/interface/events.h.T | 60 +- .../interface/jobstat.h.T | 14 +- .../interface/notification.h | 61 +- org.glite.lb.client-interface/interface/notifid.h | 74 +- .../interface/producer.h.T | 146 +- .../interface/statistics.h | 12 +- org.glite.lb.client-interface/project/build.number | 2 + .../project/configure.properties.xml | 56 +- .../project/version.properties | 8 +- org.glite.lb.client/Makefile | 11 +- org.glite.lb.client/build.xml | 4 + org.glite.lb.client/doc/README-acl | 66 + org.glite.lb.client/doc/README-fake | 4 - org.glite.lb.client/doc/README-notify | 72 + org.glite.lb.client/examples/abort_job.c | 128 ++ org.glite.lb.client/examples/change_acl.c | 78 + org.glite.lb.client/examples/job_status.c | 231 ++ org.glite.lb.client/examples/log_usertag_proxy.c | 103 - org.glite.lb.client/examples/producer_fake.c | 24 - org.glite.lb.client/project/build.number | 2 + org.glite.lb.client/project/version.properties | 8 +- org.glite.lb.client/src/ServerConnection.cpp | 61 +- org.glite.lb.client/src/logevent.c.T | 23 +- org.glite.lb.client/src/producer.c | 343 --- org.glite.lb.client/src/uiwrap.c.T | 28 +- org.glite.lb.common/Makefile | 2 +- org.glite.lb.common/build.xml | 4 + org.glite.lb.common/interface/lb_gss.h | 2 +- org.glite.lb.common/project/build.number | 2 + org.glite.lb.common/project/version.properties | 8 +- org.glite.lb.common/src/events.c.T | 22 +- org.glite.lb.common/src/il_log.c | 7 +- org.glite.lb.common/src/lb_gss.c | 39 +- org.glite.lb.logger/build.xml | 4 + org.glite.lb.logger/project/build.number | 2 + org.glite.lb.logger/project/version.properties | 8 +- org.glite.lb.logger/src/event_queue.c | 14 +- org.glite.lb.logger/src/event_store.c | 31 +- org.glite.lb.logger/src/il_master.c | 8 +- org.glite.lb.logger/src/interlogd.h | 2 +- org.glite.lb.logger/src/queue_thread.c | 17 +- org.glite.lb.server-bones/build.xml | 4 + org.glite.lb.server-bones/project/build.number | 2 + .../project/version.properties | 8 +- org.glite.lb.server/Makefile | 18 +- org.glite.lb.server/build.xml | 4 + org.glite.lb.server/project/build.number | 2 + org.glite.lb.server/project/version.properties | 8 +- org.glite.lb.ws-interface/Makefile | 20 +- org.glite.lb.ws-interface/build.xml | 26 +- org.glite.lb.ws-interface/project/build.number | 2 + .../project/version.properties | 8 +- org.glite.lb.ws-interface/src/LB.xml.T | 209 ++ org.glite.lb.ws-interface/src/puke-ug.xsl | 139 ++ org.glite.lb/build.xml | 4 + org.glite.lb/project/build.number | 2 + org.glite.lb/project/dependencies.properties | 26 +- org.glite.lb/project/events.T | 264 +-- org.glite.lb/project/types.T | 16 + org.glite.lb/project/version.properties | 8 +- org.glite.security.proxyrenewal/Makefile | 12 +- org.glite.security.proxyrenewal/build.xml | 5 + org.glite.security.proxyrenewal/config/startup | 52 +- .../project/build.number | 2 + .../project/version.properties | 8 +- org.glite.security.proxyrenewal/src/acstack.h | 79 + org.glite.security.proxyrenewal/src/commands.c | 127 +- org.glite.security.proxyrenewal/src/newformat.h | 195 ++ org.glite.security.proxyrenewal/src/renew.c | 883 +------- org.glite.security.proxyrenewal/src/renewal_locl.h | 5 + org.glite.security.proxyrenewal/src/renewd.c | 198 +- org.glite.security.proxyrenewal/src/renewd_locl.h | 20 +- org.glite.security.proxyrenewal/src/voms.c | 318 +++ org.glite.wms-utils.exception/build.xml | 5 + org.glite.wms-utils.exception/configure.ac | 5 +- .../interface/glite/wmsutils/exception/Exception.h | 13 +- org.glite.wms-utils.exception/project/build.number | 2 + .../project/version.properties | 8 +- org.glite.wms-utils.exception/src/Exception.cpp | 62 +- org.glite.wms-utils.jobid/build.xml | 5 + org.glite.wms-utils.jobid/project/build.number | 2 + .../project/version.properties | 8 +- org.gridsite.core/.cvsignore | 1 - org.gridsite.core/CHANGES | 148 -- org.gridsite.core/INSTALL | 39 - org.gridsite.core/LICENSE | 47 - org.gridsite.core/README | 3 - org.gridsite.core/VERSION | 4 - org.gridsite.core/build.xml | 223 -- org.gridsite.core/doc/README.htcp-bin | 13 - org.gridsite.core/doc/admin.html | 103 - org.gridsite.core/doc/build-apache2.sh | 79 - org.gridsite.core/doc/config.html | 192 -- org.gridsite.core/doc/findproxyfile.1 | 63 - org.gridsite.core/doc/gacl.html | 84 - org.gridsite.core/doc/htcp.1 | 147 -- org.gridsite.core/doc/htll.1 | 1 - org.gridsite.core/doc/htls.1 | 1 - org.gridsite.core/doc/htmkdir.1 | 1 - org.gridsite.core/doc/htrm.1 | 1 - org.gridsite.core/doc/httpd-fileserver.conf | 147 -- org.gridsite.core/doc/httpd-webserver.conf | 219 -- org.gridsite.core/doc/index.html | 92 - org.gridsite.core/doc/install.html | 148 -- org.gridsite.core/doc/library.html | 1 - org.gridsite.core/doc/module.html | 271 --- org.gridsite.core/doc/urlencode.1 | 46 - org.gridsite.core/doc/user.html | 302 --- org.gridsite.core/interface/gridsite-gacl.h | 188 -- org.gridsite.core/interface/gridsite.h | 273 --- org.gridsite.core/project/build.properties | 0 org.gridsite.core/project/configure.properties.xml | 9 - org.gridsite.core/project/dependencies.properties | 9 - org.gridsite.core/project/gridsite.core.csf.xml | 221 -- org.gridsite.core/project/properties.xml | 53 - org.gridsite.core/project/taskdefs.xml | 31 - org.gridsite.core/project/version.properties | 4 - org.gridsite.core/src/Doxyfile | 993 -------- org.gridsite.core/src/Makefile | 280 --- org.gridsite.core/src/delegation.h | 12 - org.gridsite.core/src/doxygen.css | 49 - org.gridsite.core/src/doxyheader.html | 1 - org.gridsite.core/src/findproxyfile.c | 122 - org.gridsite.core/src/gaclexample.c | 147 -- org.gridsite.core/src/gridsite.spec | 78 - org.gridsite.core/src/grst-delegation.c | 295 --- org.gridsite.core/src/grst_admin.h | 57 - org.gridsite.core/src/grst_admin_file.c | 1571 ------------- org.gridsite.core/src/grst_admin_gacl.c | 968 -------- org.gridsite.core/src/grst_admin_main.c | 365 --- org.gridsite.core/src/grst_gacl.c | 1154 ---------- org.gridsite.core/src/grst_http.c | 407 ---- org.gridsite.core/src/grst_x509.c | 1398 ------------ org.gridsite.core/src/htcp | Bin 29747 -> 0 bytes org.gridsite.core/src/htcp.c | 1237 ---------- org.gridsite.core/src/htproxyput.c | 565 ----- org.gridsite.core/src/mod_gridsite.c | 2357 ------------------- org.gridsite.core/src/mod_ssl-private.h | 106 - org.gridsite.core/src/proxyput-example.c | 131 -- org.gridsite.core/src/real-gridsite-admin.cgi | Bin 96256 -> 0 bytes org.gridsite.core/src/roffit | 370 --- org.gridsite.core/src/urlencode.c | 73 - 194 files changed, 6807 insertions(+), 19794 deletions(-) create mode 100644 org.glite.deployment.lb/CHANGELOG create mode 100644 org.glite.deployment.lb/project/build.number create mode 100644 org.glite.jp.common/project/build.number delete mode 100644 org.glite.jp.index/.cvsignore delete mode 100644 org.glite.jp.index/Makefile delete mode 100755 org.glite.jp.index/build.xml delete mode 100644 org.glite.jp.index/project/JobProvenanceIS.wsdl delete mode 100644 org.glite.jp.index/project/build.properties delete mode 100644 org.glite.jp.index/project/configure.properties.xml delete mode 100755 org.glite.jp.index/project/properties.xml delete mode 100644 org.glite.jp.index/project/tar_exclude delete mode 100644 org.glite.jp.index/project/version.properties delete mode 100644 org.glite.jp.index/src/simple_server.c delete mode 100644 org.glite.jp.index/src/soap_ops.c delete mode 100644 org.glite.jp.index/src/typemap.dat create mode 100644 org.glite.jp.primary/config/startup create mode 100644 org.glite.jp.primary/doc/USAGE create mode 100644 org.glite.jp.primary/doc/jpnode_install.txt create mode 100644 org.glite.jp.primary/project/build.number create mode 100644 org.glite.jp.ws-interface/project/build.number create mode 100644 org.glite.jp/project/build.number create mode 100644 org.glite.lb.client-interface/project/build.number create mode 100644 org.glite.lb.client/doc/README-acl create mode 100644 org.glite.lb.client/doc/README-notify create mode 100644 org.glite.lb.client/examples/abort_job.c create mode 100644 org.glite.lb.client/examples/change_acl.c create mode 100644 org.glite.lb.client/examples/job_status.c delete mode 100644 org.glite.lb.client/examples/log_usertag_proxy.c create mode 100644 org.glite.lb.client/project/build.number create mode 100644 org.glite.lb.common/project/build.number create mode 100644 org.glite.lb.logger/project/build.number create mode 100644 org.glite.lb.server-bones/project/build.number create mode 100644 org.glite.lb.server/project/build.number create mode 100644 org.glite.lb.ws-interface/project/build.number create mode 100644 org.glite.lb.ws-interface/src/LB.xml.T create mode 100644 org.glite.lb.ws-interface/src/puke-ug.xsl create mode 100644 org.glite.lb/project/build.number create mode 100644 org.glite.security.proxyrenewal/project/build.number create mode 100755 org.glite.security.proxyrenewal/src/acstack.h create mode 100755 org.glite.security.proxyrenewal/src/newformat.h create mode 100644 org.glite.security.proxyrenewal/src/voms.c create mode 100644 org.glite.wms-utils.exception/project/build.number create mode 100644 org.glite.wms-utils.jobid/project/build.number delete mode 100644 org.gridsite.core/.cvsignore delete mode 100644 org.gridsite.core/CHANGES delete mode 100644 org.gridsite.core/INSTALL delete mode 100644 org.gridsite.core/LICENSE delete mode 100644 org.gridsite.core/README delete mode 100644 org.gridsite.core/VERSION delete mode 100644 org.gridsite.core/build.xml delete mode 100644 org.gridsite.core/doc/README.htcp-bin delete mode 100644 org.gridsite.core/doc/admin.html delete mode 100644 org.gridsite.core/doc/build-apache2.sh delete mode 100644 org.gridsite.core/doc/config.html delete mode 100644 org.gridsite.core/doc/findproxyfile.1 delete mode 100644 org.gridsite.core/doc/gacl.html delete mode 100644 org.gridsite.core/doc/htcp.1 delete mode 100644 org.gridsite.core/doc/htll.1 delete mode 100644 org.gridsite.core/doc/htls.1 delete mode 100644 org.gridsite.core/doc/htmkdir.1 delete mode 100644 org.gridsite.core/doc/htrm.1 delete mode 100644 org.gridsite.core/doc/httpd-fileserver.conf delete mode 100644 org.gridsite.core/doc/httpd-webserver.conf delete mode 100644 org.gridsite.core/doc/index.html delete mode 100644 org.gridsite.core/doc/install.html delete mode 100644 org.gridsite.core/doc/library.html delete mode 100644 org.gridsite.core/doc/module.html delete mode 100644 org.gridsite.core/doc/urlencode.1 delete mode 100644 org.gridsite.core/doc/user.html delete mode 100644 org.gridsite.core/interface/gridsite-gacl.h delete mode 100644 org.gridsite.core/interface/gridsite.h delete mode 100644 org.gridsite.core/project/build.properties delete mode 100644 org.gridsite.core/project/configure.properties.xml delete mode 100644 org.gridsite.core/project/dependencies.properties delete mode 100644 org.gridsite.core/project/gridsite.core.csf.xml delete mode 100644 org.gridsite.core/project/properties.xml delete mode 100644 org.gridsite.core/project/taskdefs.xml delete mode 100644 org.gridsite.core/project/version.properties delete mode 100644 org.gridsite.core/src/Doxyfile delete mode 100644 org.gridsite.core/src/Makefile delete mode 100644 org.gridsite.core/src/delegation.h delete mode 100644 org.gridsite.core/src/doxygen.css delete mode 100644 org.gridsite.core/src/doxyheader.html delete mode 100644 org.gridsite.core/src/findproxyfile.c delete mode 100644 org.gridsite.core/src/gaclexample.c delete mode 100644 org.gridsite.core/src/gridsite.spec delete mode 100644 org.gridsite.core/src/grst-delegation.c delete mode 100644 org.gridsite.core/src/grst_admin.h delete mode 100644 org.gridsite.core/src/grst_admin_file.c delete mode 100644 org.gridsite.core/src/grst_admin_gacl.c delete mode 100644 org.gridsite.core/src/grst_admin_main.c delete mode 100644 org.gridsite.core/src/grst_gacl.c delete mode 100644 org.gridsite.core/src/grst_http.c delete mode 100644 org.gridsite.core/src/grst_x509.c delete mode 100644 org.gridsite.core/src/htcp delete mode 100644 org.gridsite.core/src/htcp.c delete mode 100644 org.gridsite.core/src/htproxyput.c delete mode 100644 org.gridsite.core/src/mod_gridsite.c delete mode 100644 org.gridsite.core/src/mod_ssl-private.h delete mode 100644 org.gridsite.core/src/proxyput-example.c delete mode 100644 org.gridsite.core/src/real-gridsite-admin.cgi delete mode 100755 org.gridsite.core/src/roffit delete mode 100644 org.gridsite.core/src/urlencode.c diff --git a/org.glite.deployment.lb/CHANGELOG b/org.glite.deployment.lb/CHANGELOG new file mode 100644 index 0000000..e14ac8a --- /dev/null +++ b/org.glite.deployment.lb/CHANGELOG @@ -0,0 +1,20 @@ +DATE: 21-03-2005 17:21 +[dimeglio] Implemented status method + +DATE: 21-03-2005 00:32 +[dimeglio] Added PERL5LIB env var + +DATE: 17-03-2005 17:33 +[gdiez] Stopping and starting the database before the index creation (just after the database is created and the user granted) + +DATE: 09-03-2005 23:05 +[dimeglio] Moved creation of indices inside database creation (if database + exists indices are not recreated) + +DATE: 02-03-2005 11:05 +[dimeglio] Started CHANGELOG +[dimeglio] Fixed formatting, improved display of message using glib.printXxxMessage functions +[dimeglio] Fixed some problems when starting/stopping services +[dimeglio] GLITE_USER parameter not exposed anymore in config file, use same user parameters + as WMS to allow installation on same node +[dimeglio] Increased module version number to 1.2.0 \ No newline at end of file diff --git a/org.glite.deployment.lb/build.xml b/org.glite.deployment.lb/build.xml index 0ceaee9..874c661 100644 --- a/org.glite.deployment.lb/build.xml +++ b/org.glite.deployment.lb/build.xml @@ -13,6 +13,11 @@ Revision history: $Log$ + Revision 1.5 2004/10/17 22:34:39 dimeglio + Use new installer script format + Use global filters + Use RH standard expat rpm in sdf template + Revision 1.4 2004/10/14 16:07:53 dimeglio Removed wms.thirdparty-globus-ssl-utils @@ -84,6 +89,7 @@ Load version file ========================================= --> + - + + + + + + + + + + @@ -15,32 +30,115 @@ description="Enable check of host certificates" value="true"/> - - - - - - + + + + owner + location + destination + + - - - + - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/org.glite.deployment.lb/doc/release_notes/release_notes.doc b/org.glite.deployment.lb/doc/release_notes/release_notes.doc index 5fc59f7ed7fd784df377df43e569a4d21cefc8b3..dd0cc439dc9ee6f2b756b12a1960e980e7a0c9cb 100644 GIT binary patch literal 334848 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 MH}8pm{&5Zb3PZoRsQ>@~ literal 172032 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 z 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 diff --git a/org.glite.deployment.lb/doc/release_notes/release_notes.html b/org.glite.deployment.lb/doc/release_notes/release_notes.html index 1db7585..989792a 100644 --- a/org.glite.deployment.lb/doc/release_notes/release_notes.html +++ b/org.glite.deployment.lb/doc/release_notes/release_notes.html @@ -20,8 +20,7 @@ {font-family:Times; panose-1:2 2 6 3 5 4 5 2 3 4;} @font-face - {font-family:"Univers \(W1\)"; - panose-1:0 0 0 0 0 0 0 0 0 0;} + {font-family:"Univers \(W1\)";} /* Style Definitions */ p.MsoNormal, li.MsoNormal, div.MsoNormal {margin-top:2.0pt; @@ -492,429 +491,528 @@ text-transform:uppercase'>gLite Logging & Bookkeeping Server

1. Release Description

This release contains the gLite Logging & Bookkeeping -Server module v. 0.2.0. The following sections provide additional information about +Server module v. 1.2.2. The following sections provide additional information about the release content, the module dependencies, the know bugs and issues and a list of bugs closed since the previous release. For information about installing and using the gLite Logging & Bookkeeping Server, please refer to the gLite Installation and User Guides.

-

2. Release contents

+

2. Changes in this Release

-

The gLite Logging & Bookkeeping Server v. 0.2.0 is +

This release introduces the following changes:

+ +

 

+ +
    +
  • Implemented status method
  • +
  • Added definition of PERL5LIB env var
  • +
  • Stopping and starting the database before the index + creation (just after the database is created and the user granted) to fix + access denied error
  • +
  • Moved creation of indices inside database creation (if + database exists indices must not be recreated)
  • +
  • GLITE_USER parameter is not exposed anymore in the + configuration file; instead the module uses the same user parameters as + WMS to allow installation on same node
  • +
  • LB admin tools are now installed in sbin, not in bin
  • +
  • Bug fixes (see below for the complete lists)
  • +
+ +

3. Release contents

+ +

The gLite Logging & Bookkeeping Server v. 1.2.2 is composed of the following gLite components:

 

- +
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + +
-

Component name

+

Component name

-

Version

+

Version

-

File

+

File

-

org.glite.deployment.lb

+

org.glite.deployment.lb

-

0.2.0

+

1.2.2

-

http://glite.web.cern.ch/glite/packages/I20041210/installers/glite-lb_installer.sh +

http://glite.web.cern.ch/glite/packages/R1.0/R20050331/installers/glite-lb_installer.sh

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/noarch/RPMS/glite-lb-config-0.2.0-1.noarch.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/noarch/RPMS/glite-lb-config-1.2.2-1.noarch.rpm

-

org.glite.deployment.config

+

org.glite.deployment.config

-

0.3.0

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/noarch/RPMS/glite- - config-0.3.0-1.noarch.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/noarch/RPMS/glite-config-1.0.0-1.noarch.rpm

-

glite-lb-client-interface

+

org.glite.lb.client-interface

-

0.3.1

+

1.0.2

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/i386/RPMS/glite-lb-client-interface-0.3.1-2.i386.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-lb-client-interface-1.0.2-1.i386.rpm

-

glite-lb-common

+

org.glite.lb.common

-

0.4.1

+

1.1.4

-

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/i386/RPMS/glite-lb-common-0.4.1-2.i386.rpm

+

http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-lb-common-1.1.4-1.i386.rpm

-

glite-lb-logger

+

org.glite.lb.logger

-

0.4.1

+

1.0.1

-

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/i386/RPMS/glite-lb-logger-0.4.1-3.i386.rpm

+

http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-lb-logger-1.0.1-1.i386.rpm

-

glite-lb-server

+

org.glite.lb.server

-

0.6.2

+

1.0.1

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/i386/RPMS/glite-lb-server-0.6.2-4.i386.rpm

+ 8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-lb-server-1.0.1-1.i386.rpm

-

glite-lb-server-bones

+

org.glite.lb.server-bones

-

0.1.0

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/i386/RPMS/glite-lb-server-bones-0.1.0-1.i386.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-lb-server-bones-1.0.0-1.i386.rpm

-

glite-lb-ws-interface

+

org.glite.lb.ws-interface

-

0.1.0

+

1.0.1

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/i386/RPMS/glite-lb-ws-interface-0.1.0-0.i386.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-lb-ws-interface-1.0.1-1.i386.rpm

-

glite-security-proxyrenewal

+

org.glite.security.proxyrenewal

-

0.1.1

+

1.0.11

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/i386/RPMS/glite-security-proxyrenewal-0.1.1-1.i386.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-security-proxyrenewal-1.0.11-1.i386.rpm

-

glite-wms-utils-exception

+

org.glite.wms-utils.exception

-

0.1.2

+

1.0.1

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/i386/RPMS/glite-wms-utils-exception-0.1.2-1.i386.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-wms-utils-exception-1.0.1-1.i386.rpm

-

glite-wms-utils-jobid

+

org.glite.wms-utils.jobid

-

0.1.2

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041210/bin/rhel30/i386/RPMS/glite-wms-utils-jobid-0.1.2-1.i386.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-wms-utils-jobid-1.0.0-1.i386.rpm

+
+

org.glite.security.voms

+
+

1.2.32

+
+

http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/glite-security-voms-1.2.32-1.i386.rpm

+
+

org.gridsite.core

+
+

1.1.5

+
+

http://glite.web.cern.ch/glite/packages/R1.0/R20050331/bin/rhel30/i386/RPMS/gridsite-1.1.5-1.i386.rpm

 

-

3. Dependencies

+

4. Dependencies

-

The gLite Logging & Bookkeeping Server module has the -following dependencies:

+

The gLite Logging & Bookkeeping Server v. 1.2.2 module +has the following dependencies:

 

- +
- - - - - - - + + + + + - - - - - - - - - - - - - - - - - - - - + + + + +

Component name

+ 8.0pt'>Component name

-

Version

+

Version

-

RPM file name

+

RPM file name

gLite Security Utilities

+ style='font-size:8.0pt'>gLite Security Utilities

-

0.2.0

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041210/installers/glite-security-utils_installer.sh

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/R1.0/R20050331/installers/glite-security-utils_installer.sh

+

gLite R-GMA Service Publisher

+
+

4.1.5

+
+

http://glite.web.cern.ch/glite/packages/R1.0/R20050331/installers/glite-rgma-servicetool_installer.sh

+

GPT

+ 8.0pt'>GPT

-

VDT 1.2.0

+

VDT 1.2.2

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/gpt-VDT1.2.0rh9-1.i386.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/gpt-VDT1.2.2rh9-1.i386.rpm

VDT Globus Essentials

+ 8.0pt'>VDT Globus Essentials

-

VDT 1.2.0

+

VDT 1.2.2

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/vdt_globus_essentials-VDT1.2.0rh9-1.i386.rpm

+ style='font-size:8.0pt'>http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/vdt_globus_essentials-VDT1.2.2rh9-1.i386.rpm

MySQL-server

+ 8.0pt'>MySQL-server

-

4.0.20

+

4.0.20

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/MySQL-server-4.0.20-0.i386.rpm

MySQL-client

+ 8.0pt'>MySQL-client

-

4.0.20

+

4.0.20

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/MySQL-client-4.0.20-0.i386.rpm

ares

+ 8.0pt'>ares

-

1.1.1

+

1.1.1

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/ares-1.1.1-EGEE.i386.rpm

myproxy

+ 8.0pt'>myproxy

-

1.14

+

1.14

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/myproxy-1.14-EGEE.i386.rpm

perl-Expect.pm

+ 8.0pt'>perl-Expect.pm

-

1.01

+

1.01

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/per-Expect.pm-1.01-9.i386.rpm

+

Java SDK/JRE

+
+

1.4.2

+
+

http://java.sun.com/j2se/1.4.2/download.html

+

 

-

4. Known bugs and issues

+

5. Known bugs and issues

This release has the following bugs and issues. Bug numbers refer to the gLite Bug Tracking system @@ -924,175 +1022,436 @@ href="https://savannah.cern.ch/bugs/?group=jra1mdw">https://savannah.cern.ch/bug

 

+
    +
  • No removal procedure is provided + with this release apart from the removal of the RPMS. Any account, group + or other resource created during the module configuration must be manually + cleaned.
  • +
+ +

 

+ +

Known open bugs:

+ +

 

+ - - + - - + + - - + - + + + + + + + + + + +

Bug number

Description

+

 

+
+

 #5125

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=6412"> #6412

glite-lb-bkserverd - start/stop/status displays usage options 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=6412">--start and --stop options not + documented in glite-ce-config.py, glite-lb-config.py 

+
+

 

 #5202

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7053"> #7053

no RPM provides the - lb-local-logger daemon -  

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7053">LB configuration fails if the + mysql root pwd is set 

+
+

 

+

 #5248

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7180"> #7180

When running - "glite-lb-bkserverd start", glite-lb-bkserverd doesn't start in - background 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7180">Logging & Bookkeping UI  

+
+

 

 #5833

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7237"> #7237

-

all jobs in SUBMITTED after a - job storm 

+
+

Intermittent errors with job + submission 

+
+

 

 #5903

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7300"> #7300

glite-lb-bkserverd script gives - bash: /root/.bashrc: Permission denied error  

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7300">update of the lb instructions + at the end of the installer script  

+
+

 

 #5904

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7305"> #7305

glite-lb-bkserverd does not - check default location for credentials 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7305">lb.database.username paramenter + in config file 

+
+

 

 #5926

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7307"> #7307

Default user should not be used - in the init.d scripts 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7307">lb config script does _not_ + fail if mysql root password is set 

+
+

 

 #5932

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7321"> #7321

credential file created in - /var/tmp is unnecessary 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7321">creation of indices fails + randomly 

+
+

 

 #5934

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7324"> #7324

service start and stop notifications - are inconsistent for glite-lb-bkserverd init,d script 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7324">lb-bkserver is running with no + pid 

+
+

 

+
+

 #7389

+
+

LB server and WMS local logger + related issues 

+
+

 

-

 

+

 

-

No removal procedure is -provided with this release apart from the removal of the RPMS. Any account, -group or other resource created during the module configuration must be -manually cleaned.

+

Bugs fixed in this or previous releases, but not yet officially +tested:

+ +

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bug number

+
+

Description

+
+

 

+
+

 #5850

+
+

glite-lb-config.py has + glite.location and globus.location not set in params[] 

+
+

 

+
+

 #5908

+
+

Environment variables set via + the configuration script are not passed to daemon startup scripts 

+
+

 

+
+

 #6075

+
+

glite-lb-config.py crashes with + KeyError: GLITE_CERT_DIR 

+
+

 

+
+

 #6366

+
+

LB install script:: Fails but + no error reported 

+
+

 

+
+

 #6415

+
+

glite-lb-bkserver does not + start and blocks execution of glite-lb-config.py 

+
+

 

+
+

 #6689

+
+

glite-proxy-renewd starts the + daemon glite-proxy-renewd as GLITE_USER which is glite-lb i.e. wrong 

+
+

 

+
+

 #6722

+
+

glite-job-status -all doesn't + work 

+
+

 

+
+

 #7296

+
+

glite-lb-config.py crashes with + a TypeError exception 

+
+

 

+

 

-

5. Bugs closed since last release

+

6. Bugs closed since last release

@@ -1101,96 +1460,1190 @@ href="https://savannah.cern.ch/bugs/?group=jra1mdw">https://savannah.cern.ch/bug - - - + + + + - + + + + - - + + + + + + + + + + + + - + + + + + + +

Bug number

Description

+ +

 #5833

+
+

all jobs in SUBMITTED after a + job storm 

+

 #4627

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=5897"> #5897

+

I20041203 LB installation + script has a missing dependency  

+

no licence found in lb packages 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=5910"> #5910

+
+

glite-lb configuration scripts + don't set GLITE_USER environment 

+

 #5236

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=5925"> #5925

+

Running glite-lb script removes + mysql.sock file  

+
+

 #6416

+
+

the BKserver on the LB machine + needs a symlink and the script doesn't check for it 

+
+

 #7032

+
+

The LB installer fails with an + RPM not found message 

+

LB install/config documentation - has some errors 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7152"> #7152

+
+

The LB installer tries to + install gridsite with a wrong rpm name 

 #5912

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7351"> #7351

glite-lb-bkserver daemon looks - hangs is /tmp/mysql.sock is not present 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=7351">Star/restart of LB services  

+

 #7401

+
+

The first time the LB config + script is run it fails creating the db indices 

+
+

 #7423

+
+

'/etc/rc.d/init.d/gLite status' + not working correctly in LB 

+
+ +

 

+ +
+
+ +

7. Previous Releases

+ +

7.1. Release 1.1.0

+ +

7.1.1. Release Description

+ +

This release contains the gLite Logging & Bookkeeping +Server module v. 1.1.0. The following sections provide additional information about +the release content, the module dependencies, the know bugs and issues and a +list of bugs closed since the previous release. For information about +installing and using the gLite Logging & Bookkeeping Server, please refer +to the gLite Installation and User Guides.

+ +

7.1.2. Changes in this Release

+ +

This release introduces the following changes:

+ +

 

+ +
    +
  • The gLite init.d script has been added to the deployment + module. The script is installed and activated by the configuration scripts + to start all LB services at boot-time
  • +
  • Bug fixes (see below for the complete lists)
  • +
+ +

7.1.3. Release contents

+ +

The gLite Logging & Bookkeeping Server v. 1.1.0 is +composed of the following gLite components:

+ +

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Component name

+
+

Version

+
+

File

+
+

org.glite.deployment.lb

+
+

1.1.0

+
+

http://glite.web.cern.ch/glite/packages/I20050225/installers/glite-lb_installer.sh +

+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/noarch/RPMS/glite-lb-config-1.1.0-1.noarch.rpm

+
+

org.glite.deployment.config

+
+

0.8.2

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/noarch/RPMS/glite- + config-0.8.2-1.noarch.rpm

+
+

org.glite.lb.client-interface

+
+

1.0.1

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-lb-client-interface-1.0.1-1.i386.rpm

+
+

org.glite.lb.common

+
+

1.1.3

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-lb-common-1.1.3-1.i386.rpm

+
+

org.glite.lb.logger

+
+

1.0.1

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-lb-logger-1.0.1-1.i386.rpm

+
+

org.glite.lb.server

+
+

1.0.1

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-lb-server-1.0.1-1.i386.rpm

+
+

org.glite.lb.server-bones

+
+

1.0.0

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-lb-server-bones-1.0.0-1.i386.rpm

+
+

org.glite.lb.ws-interface

+
+

1.0.0

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-lb-ws-interface-1.0.0-1.i386.rpm

+
+

org.glite.security.proxyrenewal

+
+

1.0.1

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-security-proxyrenewal-1.0.1-1.i386.rpm

+
+

org.glite.wms-utils.exception

+
+

1.0.0

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-wms-utils-exception-1.0.0-1.i386.rpm

+
+

org.glite.wms-utils.jobid

+
+

1.0.0

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-wms-utils-jobid-1.0.0-1.i386.rpm

+
+

org.glite.security.voms

+
+

1.2.29

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/glite-security-voms-1.2.29-22.i386.rpm

+
+

org.gridsite.core

+
+

1.1.5

+
+

http://glite.web.cern.ch/glite/packages/I20050225/bin/rhel30/i386/RPMS/gridsite-1.1.5-1.i386.rpm

+
+ +

 

+ +

7.1.4. Dependencies

+ +

The gLite Logging & Bookkeeping Server module has the +following dependencies:

+ +

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Component name

+
+

Version

+
+

RPM file name

+
+

gLite Security Utilities

+
+

0.6.1

+
+

http://glite.web.cern.ch/glite/packages/I20050225/installers/glite-security-utils_installer.sh

+
+

gLite R-GMA Service Publisher

+
+

4.1.2

+
+

http://glite.web.cern.ch/glite/packages/I20050225/installers/glite-rgma-servicetool_installer.sh

+
+

GPT

+
+

VDT 1.2.2

+
+

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/gpt-VDT1.2.0rh9-1.i386.rpm

+
+

VDT Globus Essentials

+
+

VDT 1.2.2

+
+

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/vdt_globus_essentials-VDT1.2.0rh9-1.i386.rpm

+
+

MySQL-server

+
+

4.0.20

+
+

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/MySQL-server-4.0.20-0.i386.rpm

+
+

MySQL-client

+
+

4.0.20

+
+

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/MySQL-client-4.0.20-0.i386.rpm

+
+

ares

+
+

1.1.1

+
+

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/ares-1.1.1-EGEE.i386.rpm

+
+

myproxy

+
+

1.14

+
+

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/myproxy-1.14-EGEE.i386.rpm

+
+

perl-Expect.pm

+
+

1.01

+
+

http://glite.web.cern.ch/glite/packages/externals/bin/rhel30/RPMS/per-Expect.pm-1.01-9.i386.rpm

+
+ +

 

+ +

7.1.5. Known bugs and issues

+ +

This release has the +following bugs and issues. Bug numbers refer to the gLite Bug Tracking system +database hosted on the CERN Savannah system at https://savannah.cern.ch/bugs/?group=jra1mdw +.

+ +

 

+ +
    +
  • No removal procedure is provided + with this release apart from the removal of the RPMS. Any account, group + or other resource created during the module configuration must be manually + cleaned.
  • +
  • No inet.d scripts are installed or + activated in this release. This will be fixed in the next release
  • +
+ +

 

+ +

Known open bugs:

+ +

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bug number

+
+

Description

+
+

 

+
+

 #6057

+
+

glite-lb configuration scripts + has missing dependency (CGI.pm) 

+
+

 

+
+

 #6415

+
+

glite-lb-bkserver does not + start and blocks execution of glite-lb-config.py 

+
+

 

+
+

 #6722

+
+

glite-job-status -all doesn't + work 

+
+

 

+
+

 #6838

+
+

There are no test reports + provided for the L&B Server in gLite v1.0.6 RC1 (Integration Build + I20050204) 

+
+

 

+
+

 #7032

+
+

The LB installer fails with an + RPM not found message 

+
+

 

+
+

 #7039

+
+

Problem if LD_LIBRARY_PATH is + unset 

+
+

 

+
+

 #7053

+
+

LB configuration fails if the + mysql root pwd is set 

+
+

 

+
+

 #7180

+
+

Logging & Bookkeping UI  

+
+

 

+
+ +

 

+ +

Bugs fixed in this or previous releases, but not yet tested:

+ +

 

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

Bug number

+
+

Description

+
+

 

+
+

 #5833

+
+

all jobs in SUBMITTED after a + job storm 

+
+

 

+
+

 #5850

+
+

glite-lb-config.py has + glite.location and globus.location not set in params[] 

+
+

 

+
+

 #5897

+
+

I20041203 LB installation + script has a missing dependency  

+
+

 

+
+

 #5901

+
+

mysqlaccess command fails with + Broken pipe if mysql socket file is in /tmp  

+
+

 

+
+

 #5908

+
+

Environment variables set via + the configuration script are not passed to daemon startup scripts 

+
+

 

+
+

 #5910

+
+

glite-lb configuration scripts + don't set GLITE_USER environment 

+
+

 

+
+

 #5925

+
+

Running glite-lb script removes + mysql.sock file  

+
+

 

+
+

 #6075

+
+

glite-lb-config.py crashes with + KeyError: GLITE_CERT_DIR 

+
+

 

+
+

 #6366

+
+

LB install script:: Fails but + no error reported 

+
+

 

+
+

 #6412

+
+

--start and --stop options not + documented in glite-ce-config.py, glite-lb-config.py 

+
+

 

+
+

 #6416

+
+

the BKserver on the LB machine + needs a symlink and the script doesn't check for it 

+
+

 

+
+ +

 

+ +

7.1.6. Bugs closed since last release

+ +

This release fixes the +following bugs and issues. Bug numbers refer to the gLite Bug Tracking system +database hosted on the CERN Savannah system at https://savannah.cern.ch/bugs/?group=jra1mdw

+ +

 

+ + + + -
-

 #5930

+

Bug number

-

running start on started - service is not an error.  

+
+

Description

 

-

6. Previous Releases

- -

6.1. Release 0.1.0

+

7.2. Release 1.0.0

-

6.1.1. Release Description

+

7.2.1. Release Description

This release contains the gLite Logging & Bookkeeping -Server module v. 0.1.0. The following sections provide additional information +Server module v. 1.0.0. The following sections provide additional information about the release content, the module dependencies, the know bugs and issues and a list of bugs closed since the previous release. For information about installing and using the gLite Logging & Bookkeeping Server, please refer to the gLite Installation and User Guides.

-

6.1.2. Release contents

+

7.2.2. Changes in this Release

-

The gLite Logging & Bookkeeping Server v. 0.1.0 is +

This release doesn’t contain any functional changes. It +contains a number of bug fixes in the components and the deployment module to +be submitted to testing.

+ +

However, the version number has been changed to match the +final release number 1.0.0.

+ +

7.2.3. Release contents

+ +

The gLite Logging & Bookkeeping Server v. 0.3.1 is composed of the following gLite components:

 

@@ -1219,17 +2672,17 @@ composed of the following gLite components:

-

0.1.0

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041126/installers/glite-lb_installer.sh + href="http://glite.web.cern.ch/glite/packages/I20041126/installers/glite-lb_installer.sh">http://glite.web.cern.ch/glite/packages/I20050114/installers/glite-lb_installer.sh

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/noarch/RPMS/glite-lb-config-0.1.0-1.noarch.rpm

+ href="http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/noarch/RPMS/glite-lb-config-1.0.0-1.noarch.rpm">http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/noarch/RPMS/glite-lb-config-1.0.0-1.noarch.rpm

@@ -1240,15 +2693,15 @@ composed of the following gLite components:

-

0.1.0

+

0.4.1

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/noarch/RPMS/glite- - config-0.1.0-1.noarch.rpm

+ href="http://glite.web.cern.ch/glite/packages/I20050107/bin/rhel30/noarch/RPMS/glite-%20config-0.4.1-1.noarch.rpm">http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/noarch/RPMS/glite- + config-0.4.1-1.noarch.rpm

@@ -1259,14 +2712,32 @@ composed of the following gLite components:

-

0.3.0

+

1.0.0

+ + +

http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/i386/RPMS/glite-lb-client-interface-1.0.0-1.i386.rpm

+ + + + +

glite-lb-common

+ + +

1.1.0

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/i386/RPMS/glite-lb-client-interface-0.3.0-2.i386.rpm

+ href="http://glite.web.cern.ch/glite/packages/I20050107/bin/rhel30/i386/RPMS/glite-lb-common-1.1.0-1.i386.rpm">http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/i386/RPMS/glite-lb-common-1.1.0-1.i386.rpm

@@ -1277,86 +2748,86 @@ composed of the following gLite components:

-

0.3.0

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/i386/RPMS/glite-lb-logger-0.3.0-3.i386.rpm

+ href="http://glite.web.cern.ch/glite/packages/I20050107/bin/rhel30/i386/RPMS/glite-lb-logger-1.0.0-1.i386.rpm">http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/i386/RPMS/glite-lb-logger-1.0.0-1.i386.rpm

-

glite-lb-common

+

glite-lb-server

-

0.3.0

+

1.0.0

-

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/i386/RPMS/glite-lb-common-0.3.0-2.i386.rpm

+

http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/i386/RPMS/glite-lb-server-1.0.0-1.i386.rpm

-

glite-lb-server

+

glite-lb-server-bones

-

0.5.2

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/i386/RPMS/glite-lb-server-0.5.2-4.i386.rpm

+ href="http://glite.web.cern.ch/glite/packages/I20050107/bin/rhel30/i386/RPMS/glite-lb-server-bones-1.0.0-1.i386.rpm">http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/i386/RPMS/glite-lb-server-bones-1.0.0-1.i386.rpm

-

glite-lb-server-bones

+

glite-lb-ws-interface

-

0.1.0

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/i386/RPMS/glite-lb-server-bones-0.1.0-1.i386.rpm

+ href="http://glite.web.cern.ch/glite/packages/I20050107/bin/rhel30/i386/RPMS/glite-lb-ws-interface-1.0.0-1.i386.rpm">http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/i386/RPMS/glite-lb-ws-interface-1.0.0-1.i386.rpm

-

glite-wms-utils-jobid

+

glite-security-proxyrenewal

-

0.1.2

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/i386/RPMS/glite-wms-utils-jobid-0.1.2-1.i386.rpm

+ href="http://glite.web.cern.ch/glite/packages/I20050107/bin/rhel30/i386/RPMS/glite-security-proxyrenewal-1.0.0-1.i386.rpm">http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/i386/RPMS/glite-security-proxyrenewal-1.0.0-1.i386.rpm

@@ -1367,39 +2838,39 @@ composed of the following gLite components:

-

0.1.2

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/i386/RPMS/glite-wms-utils-exception-0.1.2-1.i386.rpm

+ href="http://glite.web.cern.ch/glite/packages/I20050107/bin/rhel30/i386/RPMS/glite-wms-utils-exception-1.0.0-1.i386.rpm">http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/i386/RPMS/glite-wms-utils-exception-1.0.0-1.i386.rpm

-

glite-security-proxyrenewal

+

glite-wms-utils-jobid

-

0.1.0

+

1.0.0

http://glite.web.cern.ch/glite/packages/I20041126/bin/rhel30/i386/RPMS/glite-security-proxyrenewal-0.1.0-1.i386.rpm

+ href="http://glite.web.cern.ch/glite/packages/I20050107/bin/rhel30/i386/RPMS/glite-wms-utils-jobid-1.0.0-1.i386.rpm">http://glite.web.cern.ch/glite/packages/I20050114/bin/rhel30/i386/RPMS/glite-wms-utils-jobid-1.0.0-1.i386.rpm

 

-

6.1.3. Dependencies

+

7.2.4. Dependencies

The gLite Logging & Bookkeeping Server module has the following dependencies:

@@ -1432,13 +2903,14 @@ following dependencies:

-

0.2.0

+

0.4.0

http://glite.web.cern.ch/glite/packages/I20041126/installers/glite-security-utils_installer.sh

+ style='font-size:10.0pt'>http://glite.web.cern.ch/glite/packages/I20050114/installers/glite-security-utils_installer.sh

@@ -1585,7 +3057,7 @@ following dependencies:

 

-

6.1.4. Known bugs and issues

+

7.2.5. Known bugs and issues

This release has the following bugs and issues. Bug numbers refer to the gLite Bug Tracking system @@ -1598,39 +3070,38 @@ href="https://savannah.cern.ch/bugs/?group=jra1mdw">https://savannah.cern.ch/bug - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Bug number

Description

+

 #5125

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=5202"> #5202

+

glite-lb-bkserverd - start/stop/status displays usage options 

+ href="https://savannah.cern.ch/bugs/?func=detailitem&item_id=5202">no RPM provides the + lb-local-logger daemon -  

 #5248

https://savannah.cern.ch/bug background 

+

 #5833

+
+

all jobs in SUBMITTED after a + job storm 

+
+

 #5850

+
+

glite-lb-config.py has + glite.location and globus.location not set in params[] 

+
+

 #5897

+
+

I20041203 LB installation + script has a missing dependency  

+
+

 #5900

+
+

location of mysql.sock file  

+
+

 #5901

+
+

mysqlaccess command fails with + Broken pipe if mysql socket file is in /tmp

+
+

 #5903

+
+

glite-lb-bkserverd script gives + bash: /root/.bashrc: Permission denied error  

+
+

 #5904

+
+

glite-lb-bkserverd does not + check default location for credentials 

+
+

#5910

+
+

glite-lb configuration scripts + don't set GLITE_USER environment 

+
+

 #5925

+
+

Running glite-lb script removes + mysql.sock file  

+
+

 #5926

+
+

Default user should not be used + in the init.d scripts 

+
+

 #5932

+
+

credential file created in + /var/tmp is unnecessary 

+
+

 #5934

+
+

service start and stop + notifications are inconsistent for glite-lb-bkserverd init,d script 

+
+

 #6057

+
+

glite-lb configuration scripts + has missing dependency (CGI.pm) 

+
+

#6075

+
+

glite-lb-config.py crashes with + KeyError: GLITE_CERT_DIR 

+

 

@@ -1653,12 +3333,11 @@ manually cleaned.

text-align:left;text-autospace:none'> 

-

6.1.5. Bugs closed since last release

+

7.2.6. Bugs closed since last release

This release fixes the -following bugs and issues. Since there are no previous public releases, this -list refers to the previous development release. Bug numbers refer to the gLite -Bug Tracking system database hosted on the CERN Savannah system at https://savannah.cern.ch/bugs/?group=jra1mdw  

@@ -1667,44 +3346,13 @@ href="https://savannah.cern.ch/bugs/?group=jra1mdw">https://savannah.cern.ch/bug - - - - - - - - - -
-

Bug number

+

Bug number

-

Description

-
-

 #4627

-
-

no licence found in lb packages 

-
-

 #5236

-
-

LB install/config documentation - has some errors 

+

Description

diff --git a/org.glite.deployment.lb/doc/release_notes/release_notes.pdf b/org.glite.deployment.lb/doc/release_notes/release_notes.pdf index 353c3a28a37959364d92fe9221a4253f160322af..4b071fabd9aae0a6c4eeada184a589162f22e6f2 100644 GIT binary patch literal 277829 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�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 S(*OJNFVsO8P2tE+$^QUoBQiYz diff --git a/org.glite.deployment.lb/project/build.number b/org.glite.deployment.lb/project/build.number new file mode 100644 index 0000000..0c26c70 --- /dev/null +++ b/org.glite.deployment.lb/project/build.number @@ -0,0 +1,2 @@ +#Tue Mar 22 11:03:41 CET 2005 +module.build=211 diff --git a/org.glite.deployment.lb/project/glite-lb.sdf.xml.template b/org.glite.deployment.lb/project/glite-lb.sdf.xml.template index 9fd493f..098c107 100644 --- a/org.glite.deployment.lb/project/glite-lb.sdf.xml.template +++ b/org.glite.deployment.lb/project/glite-lb.sdf.xml.template @@ -10,9 +10,9 @@ - + + + + + + + + + + + - diff --git a/org.glite.deployment.lb/project/glite-lb.spec b/org.glite.deployment.lb/project/glite-lb.spec index cf7c650..a4bc55e 100644 --- a/org.glite.deployment.lb/project/glite-lb.spec +++ b/org.glite.deployment.lb/project/glite-lb.spec @@ -8,7 +8,7 @@ Group:System/Application Prefix:/opt/glite BuildArch:noarch BuildRoot:%{_builddir}/%{name}-%{version} -Requires: glite-lb-common, glite-lb-logger, glite-lb-server, glite-security-proxyrenewal, glite-lb-client-interface, MySQL-server, MySQL-client, expat, ares,vdt_globus_essentials, glite-wms-utils-jobid, glite-wms-utils-exception, myproxy, perl-Expect.pm +Requires: glite-config, glite-rgma-servicetool-config, glite-lb-client-interface, glite-lb-ws-interface, glite-lb-logger, glite-lb-common, glite-lb-server, glite-lb-server-bones, glite-wms-utils-jobid, glite-wms-utils-exception, glite-security-proxyrenewal, glite-security-voms, gridsite, MySQL-server, MySQL-client, ares, vdt_globus_essentials, gpt, myproxy, perl-Expect.pm AutoReqProv:no Source:glite-lb.tar.gz diff --git a/org.glite.deployment.lb/project/lxscript-rpm.xsl b/org.glite.deployment.lb/project/lxscript-rpm.xsl index 79eb3dc..e20f297 100644 --- a/org.glite.deployment.lb/project/lxscript-rpm.xsl +++ b/org.glite.deployment.lb/project/lxscript-rpm.xsl @@ -9,6 +9,7 @@ omit-xml-declaration="yes"/> + @@ -52,10 +53,24 @@ function parseRPMList() RPMLIST=$newRPMLIST } +#Parse the SCRIPTLIST to execute all scripts +function parseScriptList() +{ + for i in $SCRIPTLIST + do + if [ "$INSTALL" = "true" ]; then + $i + else + $i -u + fi + done +} #Downloads and install the module RPMS function install() { + + INSTALL=true version echo echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx @@ -75,6 +90,14 @@ function install() + # Download scripts from repository + + + true + + + + # Download dependencies RPMS from repository @@ -90,6 +113,10 @@ function install() + + # Download and install subservices + parseScriptList + # Install all RPMS echo @@ -98,12 +125,35 @@ function install() echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx echo parseRPMList - rpm -Uvh $RPMLIST - echo - echo Done! + if [ ! -z "$RPMLIST" ]; then + rpm -Uvh $RPMLIST + rpm_return=$? + else + echo All required RPMS are already installed + rpm_return=0 + fi + if [ "$rpm_return" == "0" ]; then + echo + echo Done! + echo + echo Before using the gLite LB, please create or update the configuration + echo file /opt/glite/etc/config/glite-lb.cfg.xml + echo and run the configuration script + echo /opt/glite/etc/config/scripts/glite-lb-config.py. + echo A template is provided in + echo /opt/glite/etc/config/templates/glite-lb.cfg.xml + else + echo + echo An error occurred while installing the LB RPMS. + echo Most likely one or more of the RPMS to be installed require + echo additional dependencies or are older than already installed packages. + echo Please refer to the rpm error message above for more details. + fi echo - echo For more information refer to the gLite Installation and User Guides or to the gLite web site \(http:\/\/www.glite.org\) - echo Please report problems and comments to the gLite Team at project-eu-egee-middleware-integration-support@cern.ch + echo For more information refer to the gLite Installation and User Guides + echo or to the gLite web site \(http:\/\/www.glite.org\) + echo Please report problems and comments to the gLite Team at + echo project-eu-egee-glite-bugs@cern.ch cd .. } @@ -144,8 +194,16 @@ function uninstall() echo xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx echo rpm -ev $RPMLIST - echo - echo Done! + if [ "$?" == "0" ]; then + echo + echo Done! + else + echo + echo An error occurred while removing the LB RPMS. + echo Most likely one or more of the RPMS to be removed have + echo dependent packages. + echo Please refer to the rpm error message above for more details. + fi } ############################################################################### @@ -209,6 +267,28 @@ install exit 0 + + + _installer.sh + + +wget -N --non-verbose +if [ ! -f "" ] +then + echo + echo ERROR: could not be downloaded! + exit 1 +fi +chmod u+x +SCRIPTLIST="$SCRIPTLIST ./" + + +SCRIPTLISTUn="$SCRIPTLISTUn ./ -u " + + + + + --..rpm diff --git a/org.glite.deployment.lb/project/version.properties b/org.glite.deployment.lb/project/version.properties index 61f3e64..4e52c78 100644 --- a/org.glite.deployment.lb/project/version.properties +++ b/org.glite.deployment.lb/project/version.properties @@ -1,4 +1,4 @@ -#Thu Dec 09 08:14:11 CET 2004 -module.version=0.2.0 -module.build=68 -module.age=1 + +module.version = 1.2.2 +module.age = 1 + \ No newline at end of file diff --git a/org.glite.jp.common/build.xml b/org.glite.jp.common/build.xml index f20263f..61af5c7 100755 --- a/org.glite.jp.common/build.xml +++ b/org.glite.jp.common/build.xml @@ -12,6 +12,9 @@ Revision history: $Log$ + Revision 1.2 2004/11/22 13:36:42 dimeglio + First version of this file + Revision 1.1.1.1 2004/10/15 09:49:02 akrenek --> @@ -71,6 +74,8 @@ Load version file ========================================= --> + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.glite.jp.index/project/JobProvenanceIS.wsdl b/org.glite.jp.index/project/JobProvenanceIS.wsdl deleted file mode 100644 index 26f97a4..0000000 --- a/org.glite.jp.index/project/JobProvenanceIS.wsdl +++ /dev/null @@ -1,531 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Register job with JP primary storage. -Job registration in LB is propagated to JP immediately so that JP is aware of the job, -despite no furhter information is available in it. - -Input: JobId - -Output: N/A - -Faults: GenericJPFault - - - - - - - Initiate upload of of sandbox/dump of job life log from LB. -WM component responsible for job sandbox management and LB server call JP to declare -intention to upload intput/output sandbox and job life log. - -Input: - -uclass: type of the upload - INPUT_SANDBOX, OUTPUT_SANDBOX, JOB_LOG - -commitTimeout: upper limit on time for which JP waits for committing this upload transaction - -contentType: MIME type of the uploaded file - -Output: - -destination: URL where the client should upload the file - -commitBefore: acutual time when the upload transaction times out - -Faults: GenericJPFault - - -Initiate upload of of sandbox/dump of job life log from LB. - - - - - - Confirm upload. -Should be called after a file upload initiaded with StartUpload is finished. - -Input: - -destination: Upload destination URL (to match with the original request) - -Output: - -Faults: GenericJPFault - - - - - - - Record a value of user tag. -JP tags are either standalone or override values of their LB counterparts. -However, JP tag values are still distinguishable those inherited from LB. -JP tags may be either strings or blobs. - -Input: - -jobid: - -tag: structure containing name, timestamp, optional sequence number to order tag values -without relying on timestamps, and string or blob value. - -Output: N/A - -Faults: GenericJPFault - - - - - - - Start feeding JP index server. -Called by the index server to start batch feed, and optionally also subscribe for incremental feed. - -JP index server subscribes with JP primary storage using a query -containing conditions on primary metadata and a list of queryable attributes -of the index server (i.e. data which should be sent to the index server). - -When a matching job record is created or modified within the primary storage -the job record data are sent to the subscribed index server. - -The subscription is soft-state, it expires after certain time unless refreshed by the client explicitely. - -In the batch mode the query has the same form -with additional flag asking for all matching records (i.e.\ not only -arriving afterwards). - -Input: - -destination: where to send the job record data - -attributes: which job record attributes should be sent to the requesting index server - -conditions: list of query conditions. Each conditions has the form Attribute Operator Value, -where Attribute is any of job record attributes and Operator is one of EQUAL, UNEQUAL, LESS, GREATER, WITHIN. - -continuous: flag determining that the query is incremental (not batch) - -Output: - -feedId: unique Id of the feed request, to be used in refresh, cancelation etc. - -expires: when the feed times out. Must be refreshed before this time. - -Faults: GenericJPFault - - - - - - - Extend batch feed subscription (used by index server) - -Input: feedId returned previously by FeedIndex - -Output: the same as for FeedIndex - -Faults: GenericJPFault - - - - - - - Retrieve job record URL's when jobid is known -Used either to bypass JP index server query for this specific case, or after the index server query to -retrieve actual job record. - -Input: jobid - -Output: - -jobLog, inputSandbox, outputSandbox, tags: URL's to components of the job record. - -Faults: GenericJPFault - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Job Provenance Primary Storage service - - - - - - - - - - - - - - - - - - - - - - Store or update information on jobs within the JP index server. -Called directly by the primary storage, used for both batch and incremental feed. - -Input: - -data: list of job record updates. Each contains jobid, list of JP attribute values and user tag values. - -feedDone: flag indicating end of batch feed. (In order to avoid potential problems with buffer allocation -the huge dataset of batch feed is split into reasonable chunks and delivered with more UpdateJobs calls.) - -Output: N/A - -Faults: GenericJPFault - - - - - - - - - Retrieve pointers to job records of jobs matching a query. -Input: conditions - list of lists of query conditions. - Elements of the inner lists refer to a single job attribute, the conditions are or-ed. - Elements of the outer list may refer to different job attributes, they are and-ed. - -Output: - -jobs: list of JobId, PSContact (URL of the primary storage which manges this job) pairs - -Faults: GenericJPFault - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Job Provenance Index service - - - - - - - diff --git a/org.glite.jp.index/project/build.properties b/org.glite.jp.index/project/build.properties deleted file mode 100644 index e69de29..0000000 diff --git a/org.glite.jp.index/project/configure.properties.xml b/org.glite.jp.index/project/configure.properties.xml deleted file mode 100644 index 72af8f4..0000000 --- a/org.glite.jp.index/project/configure.properties.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - -top_srcdir=.. -builddir=build -stagedir=${stage.abs.dir} -distdir=${dist.dir} -globalprefix=${global.prefix} -lbprefix=${subsystem.prefix} -package=${module.package.name} -PREFIX=${install.dir} -version=${module.version} -glite_location=${with.glite.location} -globus_prefix=${with.globus.prefix} -expat_prefix=${with.expat.prefix} -gsoap_prefix=${with.gsoap.prefix} -ares_prefix=${with.ares.prefix} -thrflavour=${with.globus.thr.flavor} -nothrflavour=${with.globus.nothr.flavor} -cppunit=${with.cppunit.prefix} -jpproject=${subsystem.project.dir} -project=${component.project.dir} - - - diff --git a/org.glite.jp.index/project/properties.xml b/org.glite.jp.index/project/properties.xml deleted file mode 100755 index 5f56392..0000000 --- a/org.glite.jp.index/project/properties.xml +++ /dev/null @@ -1,52 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.glite.jp.index/project/tar_exclude b/org.glite.jp.index/project/tar_exclude deleted file mode 100644 index e1fcd1a..0000000 --- a/org.glite.jp.index/project/tar_exclude +++ /dev/null @@ -1,10 +0,0 @@ -tar_exclude -CVS -build.xml -build -build.properties -properties.xml -configure.properties.xml -.cvsignore -.project -.cdtproject diff --git a/org.glite.jp.index/project/version.properties b/org.glite.jp.index/project/version.properties deleted file mode 100644 index a0d1638..0000000 --- a/org.glite.jp.index/project/version.properties +++ /dev/null @@ -1,4 +0,0 @@ -#Fri Dec 10 13:35:33 CET 2004 -module.version=0.1.0 -module.build=2 -module.age=1 diff --git a/org.glite.jp.index/src/simple_server.c b/org.glite.jp.index/src/simple_server.c deleted file mode 100644 index ccaa5a7..0000000 --- a/org.glite.jp.index/src/simple_server.c +++ /dev/null @@ -1,39 +0,0 @@ -#include "glite/jp/types.h" -#include "glite/jp/context.h" - -#include "jpis_H.h" - -int main() { - struct soap soap; - int i, m, s; // master and slave sockets - - glite_jp_context_t ctx; - - soap_init(&soap); - glite_jp_init_context(&ctx); - soap.user = (void *) ctx; - - srand48(time(NULL)); /* feed id generation */ - - m = soap_bind(&soap, NULL, 8902, 100); - if (m < 0) - soap_print_fault(&soap, stderr); - else - { - fprintf(stderr, "Socket connection successful: master socket = %d\n", m); - for (i = 1; ; i++) { - s = soap_accept(&soap); - if (s < 0) { - soap_print_fault(&soap, stderr); - break; - } - soap_serve(&soap); // process RPC request - soap_destroy(&soap); // clean up class instances - soap_end(&soap); // clean up everything and close socket - glite_jp_run_deferred(ctx); - } - } - soap_done(&soap); // close master socket - - return 0; -} diff --git a/org.glite.jp.index/src/soap_ops.c b/org.glite.jp.index/src/soap_ops.c deleted file mode 100644 index 5af7352..0000000 --- a/org.glite.jp.index/src/soap_ops.c +++ /dev/null @@ -1,81 +0,0 @@ -#include -#include - -#include "glite/jp/types.h" -#include "glite/jp/context.h" - -#include "jpis_H.h" -#include "JobProvenanceIS.nsmap" - -static struct jptype__GenericJPFaultType *jp2s_error(struct soap *soap, - const glite_jp_error_t *err) -{ - struct jptype__GenericJPFaultType *ret = NULL; - if (err) { - ret = soap_malloc(soap,sizeof *ret); - memset(ret,0,sizeof *ret); - ret->code = err->code; - ret->source = soap_strdup(soap,err->source); - ret->text = soap_strdup(soap,strerror(err->code)); - ret->description = soap_strdup(soap,err->desc); - ret->reason = jp2s_error(soap,err->reason); - } - return ret; -} - -static void err2fault(const glite_jp_context_t ctx,struct soap *soap) -{ - char *et; - struct SOAP_ENV__Detail *detail = soap_malloc(soap,sizeof *detail); - struct _GenericJPFault *f = soap_malloc(soap,sizeof *f); - - - f->jptype__GenericJPFault = jp2s_error(soap,ctx->error); - - detail->__type = SOAP_TYPE__GenericJPFault; - detail->value = f; - detail->__any = NULL; - - soap_receiver_fault(soap,"Oh, shit!",NULL); - if (soap->version == 2) soap->fault->SOAP_ENV__Detail = detail; - else soap->fault->detail = detail; -} - -static void s2jp_tag(const struct jptype__TagValue *stag,glite_jp_tagval_t *jptag) -{ - memset(jptag,0,sizeof *jptag); - jptag->name = strdup(stag->name); - jptag->sequence = stag->sequence ? *stag->sequence : 0; - jptag->timestamp = stag->timestamp ? *stag->timestamp : 0; - if (stag->stringValue) jptag->value = strdup(stag->stringValue); - else if (stag->blobValue) { - jptag->binary = 1; - jptag->size = stag->blobValue->__size; - jptag->value = (char *) stag->blobValue->__ptr; - } -} - -#define CONTEXT_FROM_SOAP(soap,ctx) glite_jp_context_t ctx = (glite_jp_context_t) ((soap)->user) - -SOAP_FMAC5 int SOAP_FMAC6 jpsrv__UpdateJobs( - struct soap *soap, - char *feed_id, - struct jptype__UpdateJobsData *jobs, - enum xsd__boolean done -) -{ - printf("%s items %d jobid %s\n",__FUNCTION__,jobs->__sizejob, - jobs->job[0]->jobid); - return SOAP_OK; -} - -SOAP_FMAC5 int SOAP_FMAC6 jpsrv__QueryJobs( - struct soap *soap, - struct jptype__IndexQuery *query, - struct jpsrv__QueryJobsResponse *resp -) -{ - puts(__FUNCTION__); - return SOAP_OK; -} - diff --git a/org.glite.jp.index/src/typemap.dat b/org.glite.jp.index/src/typemap.dat deleted file mode 100644 index 7032cb2..0000000 --- a/org.glite.jp.index/src/typemap.dat +++ /dev/null @@ -1,2 +0,0 @@ -jpsrv = http://glite.org/wsdl/services/jp -jptype = http://glite.org/wsdl/types/jp diff --git a/org.glite.jp.primary/Makefile b/org.glite.jp.primary/Makefile index 2e9b3c4..688afe0 100644 --- a/org.glite.jp.primary/Makefile +++ b/org.glite.jp.primary/Makefile @@ -129,10 +129,11 @@ distbin: rm -rf tmpbuilddir install: - -mkdir -p ${PREFIX}/bin ${PREFIX}/etc ${PREFIX}/examples ${PREFIX}/etc/init.d + -mkdir -p ${PREFIX}/bin ${PREFIX}/etc ${PREFIX}/examples ${PREFIX}/etc/init.d ${PREFIX}/share/doc/${package}-${version} + ${INSTALL} -m 755 ${daemon} ${PREFIX}/bin ${INSTALL} -m 755 jpps-test ${PREFIX}/examples/glite-jp-primary-test - + ${INSTALL} ${top_srcdir}/doc/USAGE ${PREFIX}/share/doc/${package}-${version} clean: diff --git a/org.glite.jp.primary/build.xml b/org.glite.jp.primary/build.xml index 28c0d13..a256e16 100755 --- a/org.glite.jp.primary/build.xml +++ b/org.glite.jp.primary/build.xml @@ -12,6 +12,10 @@ Revision history: $Log$ + Revision 1.3 2004/11/22 14:00:19 dimeglio + Updated to use standard files + Fixed names (was using common instead of real module name) + Revision 1.2 2004/11/22 13:55:30 dimeglio First version of this file Use central subsystem definition @@ -75,6 +79,8 @@ Load version file ========================================= --> + + + + + + + + + + + @@ -95,6 +85,7 @@ Load version file ========================================= --> + + + + +LB web service interface currently reflects the functionality of legacy +LB query API. + + + + + Flags determining which fields of job status should be retrieved. + Include also long job descriptions (JDL). + Return list of subjobs of a DAG. + Return state of the subjobs, i.e. apply other flags recursively + + + + Classification of job states. +@@@{ + for my $stat ($status->getTypesOrdered) { + my $u = uc $stat; + my $c = getTypeComment $status $stat; + gen qq{ +! $c +}; + } +@@@} + + +@@@{ + for my $n ($status->getAllFieldsOrdered) { + my $f = selectField $status $n; + if ($f->{codes}) { + my $n = getName $f; + $n = $1.ucfirst $2 while $n =~ /([[:alpha:]]*)_([[:alpha:]]*)/; + gen qq{ +! +! Auxiliary type; values of the jobStatus.$n field. +}; + for (@{$f->{codes}}) { + my $uc = uc $_->{name}; + gen qq{ +! $_->{comment} +}; + } + gen qq{ +! +}; + } + } +@@@} + + + + + Status of a job, possibly including subjobs. + Status name. +@@@{ + for my $n (getAllFieldsOrdered $status) { + selectField $status $n; + my $f = getField $status; + my $name = getName $f; + $name = $1.ucfirst $2 while $name =~ /([[:alpha:]]*)_([[:alpha:]]*)/; + my $type = $f->{type}; + my $list = 'no'; + + if ($main::baseTypes{$type}) { + $type = eval $main::types{wsdl}->{$main::baseTypes{$type}}; + $list = 'yes' + } + elsif ($f->{codes}) { + $type = $name; + } + else { + $type = getType $f; + } + + my $comment = getComment $f; +# XXX: currently nothing is "optional" as we don't know from status.T + gen qq{ +! $comment +}; + } +@@@} + + + + Value of a single user tag. + Tag name + Tag value + + + + UNIX time representation. + Seconds since Jan 1 1970 + Microseconds + + + + + Generic SOAP fault, used to deliver any LB errors. + May be returned by any of the operations. + Source component (module) of the error. + Numeric error code. + Error text corresponding to the code. + Additional description of the error (e.g. filename) + Reason of the error, coming from lower levels. + + + + + + + An element of outer list of query conditions in job queries. + It expresses possibly several conditions (records) on a single job attribute. + These conditions are logically OR-ed. + The job attribute to which the query conditions apply. + Name of the queried user tag if attr is USERTAG. + Name of the job state to which "attr = TIME" condition refers. + The conditions. + + + + Specification of a job attribute in query. + A concrete JobId + Owner of the job (X509 certificate subject). + Status of the job (see statName type). + Where the job is currently handled (hostname). + Where the job is or was scheduled to be executed. + How the job terminated (see doneCode type) + Value of particular user tag. The tag name has to be specified in queryConditions.tagName. + When the job entered a particular state. The state has to be specified in queryCondition.statName. + The job was resubmitted. + JobId of the job parend (DAG). + UNIX exit code of the job. + + + + A single query condition. + Relational operator of the condition. + Value to compare the attribute with. + Another value to compare the attribute with (op = WITHIN only). + + + + Relational operator of query conditions. + Attribute is equal to the specified value + Attribute is less than the specified value or equal + Attribute is greater than the specified value or equal + Attribute is withing a range (queryRecord.value2 must be specified) + Attribute is not equal to the specified value. + + + + A value to compare an attribute with in queries. + Exactly one of the elements must be specified. + Integer. + String. + Timestamp. + + + + + + + + Query state of a single job. + Id of the queried job. + Which data fields to retrieve. + Current state of the job. + Any error. + + + + Retrieve a list of jobs, including their states, based on + query conditions. + The conditions take the form of a list of lists. + Elements of the inner lists refer to a single job attribute, the conditions are or-ed. + Elements of the outer list may refer to different job attributes, they are and-ed. + + The query conditions. + Which data fields to retrieve. + JobId's of jobs matching the query. + States of jobs matching the query. + Any error. + + + + Return version of the service. + Returned version. + Any error. + + + + Simplified query, return all jobs of the authenticated user. + JobId's of jobs matching the query. + States of jobs matching the query. + Any error. + + + diff --git a/org.glite.lb.ws-interface/src/puke-ug.xsl b/org.glite.lb.ws-interface/src/puke-ug.xsl new file mode 100644 index 0000000..2536d40 --- /dev/null +++ b/org.glite.lb.ws-interface/src/puke-ug.xsl @@ -0,0 +1,139 @@ + + + + + + + + + + + <xsl:value-of select="@name"/> + + Operations + + + + + + + Types + + + + + + + + + + + + + + + + + + xsd: + + + + + + + + + + + + + <xsl:value-of select="@name"/> + + + Inputs: + + + + + + + N/A + + + + Outputs: + + + + + + + + + + + + <xsl:value-of select="@name"/> + + + + Structure (sequence complex type in WSDL) + Fields: ( type name description ) + + + Enumeration (restriction of xsd:string in WSDL), + exactly one of the values must be specified. + + Values: + + + Flags (sequence of restricted xsd:string in WSDL), + any number of values can be specified together. + + Values: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + (optional) + (multiple occurence) + + + + + + + + + + + + diff --git a/org.glite.lb/build.xml b/org.glite.lb/build.xml index 2ded065..3647e56 100755 --- a/org.glite.lb/build.xml +++ b/org.glite.lb/build.xml @@ -20,6 +20,9 @@ Revision history: $Log$ + Revision 1.28 2004/11/29 15:16:26 zsalvet + Add ws-interface to checkout/build machinery. + Revision 1.27 2004/11/29 13:55:02 akrenek added dependence on ws-interface @@ -152,6 +155,7 @@ Load version file ========================================= --> + + + @@ -80,6 +83,8 @@ Load version file ========================================= --> + + >Create HEADER ?? @@ -79,6 +80,7 @@ void Exception::log(const std::string& logfile) pthread_mutex_unlock( &METHOD_MUTEX); // UNLOCK } }; + string Exception::printStackTrace(){ string stack = "" ; for (unsigned int i = 0 ; i < stack_strings.size() ; i++ ){ @@ -86,25 +88,27 @@ string Exception::printStackTrace(){ } return stack +dbgMessage(); }; + vector Exception::getStackTrace(){ // make a copy of the stack vector stack = stack_strings ; - stack.push_back(dbgMessage() ) ; + stack.push_back(dbgMessage()) ; return stack; }; string Exception::dbgMessage(){ string result ; //Adding exception Name - if ( exception_name!="") - result = exception_name ; + result = exception_name; + //Adding error msg - if (error_message!="") - result +=": " + string(what()); - if (result != "") - result+="\n"; + if (error_message!="") result +=": " + string(what()); + + if (result != "") result+="\n"; + //Adding Source result +="\tat " + method_name +"[" +source_file; + //Adding line number if (line!=0){ char buffer [1024] ; diff --git a/org.glite.wms-utils.jobid/build.xml b/org.glite.wms-utils.jobid/build.xml index 220b2a6..009513f 100755 --- a/org.glite.wms-utils.jobid/build.xml +++ b/org.glite.wms-utils.jobid/build.xml @@ -21,6 +21,9 @@ Revision history: $Log$ + Revision 1.4 2004/07/21 17:53:36 eronchie + Moved out org.glite.wms.jobid from org.glite.wms and put in org.glite.wms-utils + --> @@ -80,6 +83,8 @@ Load version file ========================================= --> + + - - - - - Ant build file to build the Gridsite Core Component - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${global.prefix} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.gridsite.core/doc/README.htcp-bin b/org.gridsite.core/doc/README.htcp-bin deleted file mode 100644 index ac546fc..0000000 --- a/org.gridsite.core/doc/README.htcp-bin +++ /dev/null @@ -1,13 +0,0 @@ -Binaries (and links) are in ./bin; man pages are in ./man/man1 - -Install by copying binaries/links onto your path, or by copying htcp -and making symbolic links to htcp from htls, htll, htrm and htmkdir. - -All the .1 man pages should be copied to a suitable ./man/man1 -directory on your man path. - -If you just want to install htcp in /usr/local, then unpacking this -tgz file in /usr/local should do the trick. (Delete this README when -you're finished!) - -For more about htcp see http://www.gridsite.org/ diff --git a/org.gridsite.core/doc/admin.html b/org.gridsite.core/doc/admin.html deleted file mode 100644 index 1f7f422..0000000 --- a/org.gridsite.core/doc/admin.html +++ /dev/null @@ -1,103 +0,0 @@ -GridSite Admin Guide - -

GridSite Admin Guide

- -

-This Guide is intended for people administrating areas of GridSite -websites or fileservers, or managing GridSite's DN List groups - that is, -how to use GridSite to manage other people's access to parts of the site - -for example, people's write access to areas devoted to specific subprojects. - -

- There is a separate -User Guide - which explains how to authenticate to the server with X.509 certificates, -and how to manage files via a standard web browser or with command-line -HTTPS clients. You should be familiar with the User Guide to fully -understand this Admin Guide. - -

- You may also find the -Config Guide - useful to understand how the Apache webserver is configured with GridSite -extensions. If you are also the Apache webmaster for your site, you will -definitely need to read the Config Guide to create the httpd.conf file. -However, if you only need to manage webpages and files, then this Admin -Guide and the User Guide should be sufficient. - -

Groups and DN Lists

- -

-GridSite defines groups of people using plain text DN Lists - that is, lists -of people's certificate DNs. Each DN List has a URL which uniquely -identifies the list (and may also allow other sites to obtain the list and -use it themselves.) For example, the list of all GridPP members is -https://www.gridpp.ac.uk/dn-lists/gridpp (note that it's https:// not -http:// - this means that other sites that download the list can check the -certificate of www.gridpp.ac.uk and know they're talking to the -authoritative source of the lists.) - -

-The system can also have a number of other DN Lists which are associated with -specific groups of people and perhaps with specific areas of responsibility -of the website. If the DN List directory URI is /dn-lists/ then -there is a full list of the DN Lists exported by the server at that URI -(for example, https://www.gridpp.ac.uk/dn-lists/ ) - -

-If you have permission to modify a DN List, you can start changing it by -going to /dn-lists/ (via HTTPS), using the "Manage directory" -button and finding the URL of your DN List in the listings. You may -need to go down into a subdirectory to find your list. For -example, https://www.gridpp.ac.uk/dn-lists/atlas is in the atlas -subdirectory of /dn-lists/ (You may wish to bookmark the listing of such -a directory if you frequently work with one.) - -

-DN List directories are managed by the ACLs described in the next section, -and if you have write permission, you can edit the lists already there, and -add new lists with the same prefix (this means you can readily create your -own subgroups.) - -

Access Control Lists

- -

-DN Lists appear in the Grid Access Control Lists (GACL) used by GridSite. -These are stored as .gacl files in directories: if the .gacl file is -present, it governs access to the directory; if it is absent, then the -parent directories are searched upwards until a .gacl is found. - -

-The GridSite GACL Reference explains the XML format -of these files, but they -can be edited using the ACL editor built into the GridSite system by people -who have the Admin permission within the ACL. - -

-If you have this permission in a given directory, when you view directory -listings or files in that directory you will see the option "Manage -Directory" in the page footer. This allows you to get a listing of the -directory and the .gacl file will appear at the top if it's present. If not, -then there will be a button to create a new .gacl file with the same -permissions as have been inherited by that directory from its parent. - -

-GACL allows quite complex conditions to be imposed on access, but normally -you can think of an ACL as being composed of a number of entries, each of -which contains one condition (the required credential) and a set of allowed -and denied permissions. - -

-Credentials can be individual user's certificate names or whole groups of -certificate names if a DN List is given. (You can also specifiy hostname -patterns using Unix shell wildcards (eg *.ac.uk) or EDG VOMS attribute -certificates - see the GACL Reference for details.) - -

-Permissions can be Admin (edit the ACL), Write (create, modify or delete -files), List (browse the directory) or Read (read files.) Permissions can be -allowed or denied. If denied by any entry, the permission is not available -to that user or DN List (depending on what credential type was associated -with the Deny.) - - diff --git a/org.gridsite.core/doc/build-apache2.sh b/org.gridsite.core/doc/build-apache2.sh deleted file mode 100644 index 507be31..0000000 --- a/org.gridsite.core/doc/build-apache2.sh +++ /dev/null @@ -1,79 +0,0 @@ -#!/bin/sh -# -# Copyright (c) 2002-3, Andrew McNab, University of Manchester -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or -# without modification, are permitted provided that the following -# conditions are met: -# -# o Redistributions of source code must retain the above -# copyright notice, this list of conditions and the following -# disclaimer. -# o Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials -# provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -#--------------------------------------------------------------- -# For more information about GridSite: http://www.gridsite.org/ -#--------------------------------------------------------------- -# -# This script takes an Apache .tar.gz as the single command line argument, -# unpacks the file, modifies the httpd.spec it contains to work without -# the "-C" option to configure (which RedHat 7.3 doesnt like) and -# outputs source and binary RPMs in SRPMS and RPMS/i386 - -if [ "$1" = "" ] ; then - echo Must give a tar.gz file name - exit -fi - -export MYTOPDIR=`pwd` - -if [ -x /usr/bin/rpmbuild ] ; then - export RPMCMD=rpmbuild -else - export RPMCMD=rpm -fi - -echo "$1" | grep '\.tar\.gz$' >/dev/null 2>&1 -if [ $? = 0 ] ; then # a gzipped source tar ball - - rm -Rf $MYTOPDIR/BUILD $MYTOPDIR/BUILDROOT $MYTOPDIR/SOURCES - mkdir -p $MYTOPDIR/SOURCES $MYTOPDIR/SPECS $MYTOPDIR/BUILD \ - $MYTOPDIR/SRPMS $MYTOPDIR/RPMS/i386 $MYTOPDIR/BUILDROOT - - shortname=`echo $1 | sed 's:^.*/::' | sed 's:\.tar\.gz$::'` - - cp -f $1 SOURCES - - tar zxvf SOURCES/$shortname.tar.gz $shortname/httpd.spec - cp -f $shortname/httpd.spec SPECS - - sed -e 's/configure -C /configure /' \ - SPECS/httpd.spec >SPECS/httpd-2.spec - - $RPMCMD --define "_topdir $MYTOPDIR" \ - -ba --buildroot $MYTOPDIR/BUILDROOT SPECS/httpd-2.spec - - exit -fi - -echo I dont recognise the file type (must be .tar.gz) - -exit diff --git a/org.gridsite.core/doc/config.html b/org.gridsite.core/doc/config.html deleted file mode 100644 index 825bf49..0000000 --- a/org.gridsite.core/doc/config.html +++ /dev/null @@ -1,192 +0,0 @@ -GridSite Config Guide - -

GridSite Config Guide

- -

-This Guide is intended for webmasters setting up -GridSite with an Apache 2.0 -webserver. We assume you have root access to the server machine to do this. -There is a separate Admin Guide for -people administrating areas of GridSite -websites or fileservers, or managing GridSite's DN List groups. That is, for -people managing files on the server rather than the server itself. - -

Installation

- -

-We assume you have installed Apache 2.0 and GridSite, using the -Building and Installation Guide where necessary. -This Config Guide assumes installation has been done under /usr. For an -alternative tree like /usr/local, the relative paths should be the same. - -

-Installation should have given you an Apache 2.0 httpd binary at -/usr/sbin/httpd and a set of standard Apache 2.0 modules in -/usr/lib/httpd/modules/ including the standard mod_ssl -and our mod_gridsite.so module. - -

-GridSite also includes some commands and man pages in /usr/bin and -/usr/share/man/man1: urlencode and -htcp. - -

Certificates

- -

-You must also install the CA root certificates of the CA's -used by the users you wish to talk to. These should be installed in -/etc/grid-security/certificates as files like 01621954.0, and RPMs and tar -files for many common European and North American CAs are available from - -https://datagrid.in2p3.fr/distribution/datagrid/security/ - -

-This location also has VOMS server certificate RPMs which install into -the /etc/grid-security/vomsdir directory. You may also manually install VOMS -server certificates into that directory with any filename. (GridSite -currently parses the certificate itself when looking for a match, rather -than checking the filename.) - -

-The server itself needs a certificate to supply to clients that use HTTPS -connections. You should apply for this from your Certification Authority -(for example, the UK e-Science -CA) and your request must use the advertised hostname of your server -(the one that appears in URLs and not, for instance, the canonical name of -the host itself.) This advertised hostname should appear in the -Distinguished Name of your request. (For example -/C=UK/O=eScience/OU=Manchester/L=HEP/CN=www.gridpp.ac.uk) For compatability -with standard browsers, the /CN= component should not include any -Globus-style service name (so not /CN=host/www.gridpp.ac.uk) If -possible, you should also include the advertised hostname as a DNS Subject -Alternative Name. Consult your CA first if you're in any doubt about how to -compose your certificate request. - -

-Once you've got your certificate, -Apache uses the certificate and private key in PEM format. If you obtained -your certificate and key in PKCS#12 or .p12 format (eg by exporting from a web -browser), you can convert the .p12 file to .pem with the following commands: -

-openssl pkcs12 -in ck.p12 -clcerts -nokeys -out hostcert.pem
-openssl pkcs12 -in ck.p12 -nodes  -nocerts -out hostkey.pem
-
- -

-Copy the PEM files to /etc/grid-security/ as hostcert.pem (which -should be world readable) and hostkey.pem (which should only be readable by -root): - -

-chown root.root hostkey.pem hostcert.pem
-chmod 400 hostkey.pem
-chmod 444 hostcert.pem
-
- -

httpd.conf

- -

-/etc/httpd/conf/httpd.conf is the key to configuring the Apache 2.0 -webserver. The directives in this file determine which files the server will -publish, how they are handled, which areas are writeable and who can access -them. Through mod_gridsite.so, the GridSite system itself is configured by -directives in this file. - -

-The easiest way to get started is to examine the example httpd.conf files we -provide. - - - -

httpd-fileserver.conf

- -

-httpd-fileserver.conf is an example -configuration file to use Apache/GridSite as a read/write HTTP(S) -fileserver, including comments on how to get the server up and running. - -

httpd-webserver.conf

- -

-httpd-webserver.conf is an example -configuration file to use Apache/GridSite as a Web Server -(that is, primarily for interactive use with a browser) -including comments on how to get the server up and running. - -

GridSite Directives

- -

-The mod_gridsite reference lists all the GridSite -httpd.conf directives. - -

-To start serving files, make a directory /var/www/htdocs owned by -nobody.nobody, including the .gacl access control file described below, -and add the following directive to the HTTPS <Directory> section: - -

-GridSiteMethods GET PUT DELETE - -

-If you wish to accept Globus GSI Proxies as well as full X.509 user -certificates, set GridSiteGSIProxyLimit to the depth of proxy you -wish to accept. (As a _rough_ guide: 0=No Proxies; 1=Proxy on user's -machine; 2=Proxy owned by running Globus job; 3=Proxy delegated by a -Globus job.) - -

GACL access control

- -

-The GACL reference explains the XML access -control files used by GridSite. These allow flexible policies to be written, -in terms of X.509 user certificates, GSI proxies, VOMS attribute -certificates, DN List groups and DNS hostnames. - -

-For example, to give all clients read and list permission: -

-

-<gacl>
-<entry>
-  <any-user/>
-  <allow><read/><list/></allow>
-</entry>
-</gacl>
-
- -

-To enable writing, add DN List, Person or VOMS entries to the file. -For example: - -

-

-<gacl>
-<entry>
-  <any-user/>
-  <allow><read/><list/></allow>
-</entry>
-<entry>
-  <person>
-  <dn>/C=UK/O=eScience/OU=Manchester/L=HEP/CN=Andrew McNab</dn>
-  </person>
-  <allow><write/></allow>
-</entry>
-</gacl>
-
- -

-The GACL file that governs a directory is stored as .gacl in that directory. -If no .gacl is present, then GridSite will search the parent directories in -ascending order until one is found. - - - - diff --git a/org.gridsite.core/doc/findproxyfile.1 b/org.gridsite.core/doc/findproxyfile.1 deleted file mode 100644 index ae2f944..0000000 --- a/org.gridsite.core/doc/findproxyfile.1 +++ /dev/null @@ -1,63 +0,0 @@ -.TH findproxyfile 1 "October 2004" findproxyfile "FINDPROXYFILE Manual" -.SH NAME -.B findproxyfile -\- returns full path to GSI Proxy file -.SH SYNOPSIS -.B findproxyfile -[--proxycache=PATH] [--delegation-id=ID] [--user-dn=DN] [--outsidecache] -.SH DESCRIPTION -.B findproxyfile -returns full path to a GSI Proxy file, either in the proxy cache maintained -by the GridSite G-HTTPS and delegation portType functions, or in other -standard places. - -If a User DN is given -.B findproxyfile -uses the value of the -.B --proxycache -argument, the GRST_PROXY_PATH or the -compile time default to detemine the location of the proxy cache directory. -The directory is searched for a proxy having the given User DN and -Delegation ID. (If no Delegation ID is specificed, then the default value is -used.) - -If -.B findproxyfile -does not find a proxy or if a User DN is not given, but -.B --outsidecache -was given, then the environment variable X509_USER_PROXY and the standard -location /tmp/x509up_uUID are searched as well. - -.SH OPTIONS - -.IP "--proxycache=PATH" -Give the path of the proxy cache directory explicitly, overriding the -default and the GRST_PROXY_PATH environment variable if present. - -.IP "--delegation-id=ID" -The optional delegation ID is search for in the proxy cache in addition to -the User DN. If absent, the default Delegation ID value is searched for. - -.IP "--user-dn=DN" -The DN of the full user certificate associated with the proxy to be searched -for in the proxy cache. (This is not the DN of any proxy earlier in the -chain: it is a the DN of a certificate issued by a recognised CA.) - -.IP "--outsidecache" -If a User DN is not given, or a proxy not found in the cache, then search -for a proxy using X509_USER_PROXY environment variable and file name of -form /tmp/x509up_uUID as well. - -.SH RETURN VALUE -If a proxy is found, its full path is output on standard out. - -.SH EXIT CODES -0 is returned on succcess. Non-zero otherwise. - -.SH BUGS -In this version, no attempt is made to verify or validate the proxies. - -.SH AUTHOR -Andrew McNab - -findproxyfile is part of GridSite: http://www.gridsite.org/ diff --git a/org.gridsite.core/doc/gacl.html b/org.gridsite.core/doc/gacl.html deleted file mode 100644 index 40efdd2..0000000 --- a/org.gridsite.core/doc/gacl.html +++ /dev/null @@ -1,84 +0,0 @@ -GridSite: Grid Access Control Language - -

GridSite: Grid Access Control Language

- -

-GACL is the authorization policy language used by -GridSite GACL allows -policies to be written in terms of common Grid credentials: X.509 -identities, GSI proxies, VOMS attribute certificates and lists of X.509 -identities. - -

-GridSite both uses GACL policies and provides a GACL manipulation API for -C/C++ in the GridSite library. - -

Credentials

- -

-In GridSite 1.0.x, four credential types are supported: - -

-<person> -<dn>/O=Grid/CN=Name</dn> -</person> - -

-<voms> -<fqan>/vo.dom.ain/group</fqan> -</voms> - -

-<dn-list> -<url>https://www.vo.dom.ain/dn-lists/group</url> -</dn-list> - -

-<dns> -<hostname>host*.dom.ain</hostname> -</dns> - -

Permissions

- -

-Five permissions are supported: Admin, Write, List, Exec and Read. Admin is -permission to modify the authorization policy itself, but applications can -map the other permissions to local methods as appropriate to their -environment. For filesystems and fileservers, Write, List and Read have -their usual meanings: creating or modifying files or directories; browsing -directories; reading files. Exec is not used by GridSite itself, and -applications are free to give it a meaning within their own contexts. - -

-In 1.0.x, only per-directory GACL files are supported, and the file is stored -in the directory in question, or in one of its parent directories. (GridSite -searches upwards until it finds one.) - -

-In GACL files, the permissions are represented by single tags: -<admin/>, <write/>, <list/>, <exec/>, <read/>. -Permission -tags are contained within Allow or Deny blocks. For example: -<allow><read/><list/></allow> or -<deny><admin/></deny>. - -

Entries

- -

-Entries associate credentials with permission statements. Entries consist of -one or more credential blocks, and either an Allow or a Deny block, or both. -If multiple credentials are present in one entry, they must all be held by a -user to receive the association permissions. (So Entries provide logical AND -of credentials.) - -

Access Control Lists

- -

-ACLs consist of a list of one or more Entry blocks. When a user's credentials -are compared to the ACL, the permissions given to the user by Allow blocks -are recorded, along with those forbidden by Deny blocks. When all entries -have been evaluated, any forbidden permissions are removed from those -granted. (So Deny always wins over Allow, even between different Entries, -but otherwise ACLs provide logical OR of credentials.) - - diff --git a/org.gridsite.core/doc/htcp.1 b/org.gridsite.core/doc/htcp.1 deleted file mode 100644 index 984aaaf..0000000 --- a/org.gridsite.core/doc/htcp.1 +++ /dev/null @@ -1,147 +0,0 @@ -.TH htcp 1 "July 2004" htcp "HTCP Manual" -.SH NAME -.B htcp, htrm, htls, htll, htmkdir -\- get, put, delete or list HTTP/HTTPS files or directories -.SH SYNOPSIS -.B htcp [options] -.I Source-URL[s] [Destination URL] -.SH DESCRIPTION -.B htcp -is a client to fetch files or directory listings from remote servers using -HTTP or HTTPS, or to put or delete files or directories onto remote servers -using HTTPS. htcp is similar to scp(1), but uses HTTP/HTTPS rather than ssh -as its transfer protocol. - -When talking to an HTTPS server, htcp can run "anonymously", with a -standard X.509 user certificate and key, or with a GSI Proxy. This makes -htcp very useful in Grid environments where many users have certificates -and where jobs and users have access to GSI proxies. - -.SH URLs -htcp supports the file:, http: and https: URL schemes as sources and -destinations. If no scheme is given, the URL scheme is assumed to be file: -and relative to the current directory if not an absolute path. - -If multiple sources are given, they will be used in turn and the destination -must be a directory (directories are indicated by a trailing /) However, -source and destination cannot both refer to remote servers. - -.SH OPTIONS -.IP "-v/--verbose" -Turn on debugging information. Used once, this option will enable htcp's -messages to stderr. Used twice, will also enable the underlying libcurl -messages. - -.IP "--delete" -Instead of copying files, delete all the URLs given on the command line. -Calling the program as htrm has the same effect. - -.IP "--list" -.br -Instead of copying files, output lists of files located in the URL-directories -given on the command line. Calling the program as htls has the same effect. - -.IP "--long-list" -Instead of copying files, output long listings of files located in the -URL-directories given on the command line. If available, the size in bytes -and modification time of each file is given. Calling the program as -htll has the same effect. - -.IP "--mkdir" -Instead of copying files, attempt to create a directory on a remote server -with HTTP PUT. The server must support the convention that PUT to a URL with -a trailing slash means create a directory. No file body is sent. Calling the -program as htmkdir has the same effect. - -.IP "--anon" -.br -Do not attempt to use X.509 user certificates or GSI proxies to authenticate -to the remote HTTPS server. This means you are "anonymous", but the server's -identity may still be verified and the connection is still encrypted. - -.IP "--cert and --key " -Path to the PEM-encoded -X.509 or GSI Proxy user certificate and key to use for HTTPS -connections, intead of "anonymous mode." If only one of --key or --cert -is given, then that will be tried for both. If neither is given, then the -following order of precedence is used: -the file name held by the variable X509_USER_PROXY; the file -/tmp/x509up_uID (with Unix UID equal to ID); the file names held by -X509_USER_CERT / X509_USER_KEY; the files ~/.globus/usercert.pem and -~/.globus/userkey.pem (where ~/ is the home directory of the user.) - -.IP "--capath " -Path to the PEM-encoded CA root certificates to use when -verifying remote servers' host certificates in HTTPS connections. Ideally -this should be a directory of hash.0 files as described in the OpenSSL -verify(1) man page, but a file may be used instead. If --capath is not -given, the value of the environment variable X509_CERT_DIR will be tried. -If this is not valid, then /etc/grid-security/certificates will be used. - -.IP "--no-verify" -Do not use CA root certificates to verify remote servers' host certificates. -This is useful for testing sites before their certificate is set up properly, -but leaves you vulnerable to "man in the middle" attacks by hostile servers -masquerading as your target. - -.IP "--downgrade-size " -Try to use HTTP-Downgrade for HTTPS URLs. Compatible servers will perform -authentication and authorization on the HTTPS connection and then redirect -to HTTP for the GET or PUT file transfer. htcp makes the HTTP request using -the GRID_AUTH_ONETIME single-use passcode obtained via HTTPS. The downgrade -option will be ignored for directory operations, HTTP URLs, or if the file -size is less than the value given. If a downgraded transfer isn't possible, -a normal HTTPS data transfer will be done. - -.SH FILES -.IP /tmp/x509up_uID -Default GSI Proxy file for Unix UID equal to ID. - -.IP /etc/grid-security/certificates -Default location for trusted Certification Authority root certificates to use -when checking server certificates. - -.IP /tmp/.ca-roots-XXXXXX -Prior to 7.9.8, the underlying curl library did not support the CA root -certificates directory. -If built with an old version of libcurl, htcp will concatenate the -certificates in the CA roots directory into a unique temporary file and use -that. - -.SH ENVIRONMENT - -.IP X509_CERT_DIR -Holds directory to search for Certification Authority root certificates when -verifying server certificates. (Tried if --capath is not given on the -command line.) - -.IP X509_USER_PROXY -Holds file name of a GSI Proxy to use as user certificate. (Tried if --cert or ---key are not given on the command line.) - -.IP "X509_USER_CERT and X509_USER_KEY" -Holds file name of X.509 user certificate and key. (Tried if X509_USER_PROXY -is not valid.) - -.SH EXIT CODES -0 is returned on complete success. Curl error codes are returned when -reported by the underlying curl library, and CURLE_HTTP_RETURNED_ERROR (22) -is returned when the HTTP(S) server returns a code outside the range 200-299. -The manpage libcurl-errors(3) lists all the curl error codes. - -.SH TO DO -Recursive copying. Server-side wildcards. Parallel streams. Error recovery. - -.SH BUGS -Not enough beta testing (hint hint...) - -.SH AUTHOR -Andrew McNab - -htcp is part of GridSite: http://www.gridsite.org/ -.SH "SEE ALSO" -.BR scp(1), -.BR curl(1), -.BR wget(1), -.BR verify(1), -.BR libcurl-errors(3) diff --git a/org.gridsite.core/doc/htll.1 b/org.gridsite.core/doc/htll.1 deleted file mode 100644 index 11a60d1..0000000 --- a/org.gridsite.core/doc/htll.1 +++ /dev/null @@ -1 +0,0 @@ -.so man1/htcp.1 diff --git a/org.gridsite.core/doc/htls.1 b/org.gridsite.core/doc/htls.1 deleted file mode 100644 index 11a60d1..0000000 --- a/org.gridsite.core/doc/htls.1 +++ /dev/null @@ -1 +0,0 @@ -.so man1/htcp.1 diff --git a/org.gridsite.core/doc/htmkdir.1 b/org.gridsite.core/doc/htmkdir.1 deleted file mode 100644 index 11a60d1..0000000 --- a/org.gridsite.core/doc/htmkdir.1 +++ /dev/null @@ -1 +0,0 @@ -.so man1/htcp.1 diff --git a/org.gridsite.core/doc/htrm.1 b/org.gridsite.core/doc/htrm.1 deleted file mode 100644 index 11a60d1..0000000 --- a/org.gridsite.core/doc/htrm.1 +++ /dev/null @@ -1 +0,0 @@ -.so man1/htcp.1 diff --git a/org.gridsite.core/doc/httpd-fileserver.conf b/org.gridsite.core/doc/httpd-fileserver.conf deleted file mode 100644 index 9bd51e2..0000000 --- a/org.gridsite.core/doc/httpd-fileserver.conf +++ /dev/null @@ -1,147 +0,0 @@ -############################################################################## -## GridSite httpd-fileserver.conf - Andrew McNab -## -## Example configuration file for GridSite as an HTTP(S) fileserver. -## -## For GridSite documentation, see http://www.gridsite.org/ -## -## This file should be renamed /etc/httpd/conf/httpd.conf and Apache -## restarted to use Apache2/GridSite as a simple HTTP(S) fileserver. -## -## You do not need to install the GridSite mod_ssl.so module if you -## do not wish to use Globus Proxies or VOMS attributes, but you must -## have the mod_gridsite.so in /usr/lib/httpd/modules -## -## We're assuming you have (a) the host's hostcert.pem and hostkey.pem -## in /etc/grid-security/ and (b) the Certification Authorities' you -## trust have their root certs in /etc/grid-security/certificates -## -## (You can get RPMs for many European and North American Grid CAs -## from https://datagrid.in2p3.fr/distribution/datagrid/security/ ) -## -## If you want to use DN Lists in ACLs, they should be placed/downloaded -## in /etc/grid-security/dn-lists/ -## -## To start serving files, make a directory /var/www/htdocs owned by -## nobody.nobody, including the file .gacl containing: -## -## -## -## -## -## -## -## -## To enable writing, add DN List, Person or VOMS entries to the GACL -## (see the GridSite GACL document for the syntax.) For example: -## -## -## -## -## -## -## -## -## /C=UK/O=eScience/OU=Manchester/L=HEP/CN=Andrew McNab -## -## -## -## -## -## and add the following directive to the HTTPS section: -## -## GridSiteMethods GET PUT DELETE -## -## If you wish to accept Globus GSI Proxies as well as full X.509 user -## certificates, set GridSiteGSIProxyLimit to the depth of proxy you -## wish to accept. -## -## (As a _rough_ guide: 0=No Proxies; 1=Proxy on user's machine; 2=Proxy -## owned by running Globus job; 3=Proxy delegated by a Globus job.) -## -## With this done and Apache restarted, you can upload a file with: -## -## curl -v --cert ~/.globus/usercert.pem --key ~/.globus/userkey.pem \ -## --capath /etc/grid-security/certificates --upload-file /tmp/tmp.txt \ -## https://INSERT.HOSTNAME.HERE/tmp.txt -## -## (or with --cert /tmp/x509up_u`id -u` --key /tmp/x509up_u`id -u` to use -## a Globus GSI Proxy created with grid-proxy-init.) -############################################################################## - -ServerRoot "/etc/httpd" - -PidFile logs/httpd.pid - -Timeout 300 -KeepAlive On -MaxKeepAliveRequests 100 -KeepAliveTimeout 15 - -LoadModule log_config_module /usr/lib/httpd/modules/mod_log_config.so -LoadModule ssl_module /usr/lib/httpd/modules/mod_ssl.so -LoadModule gridsite_module /usr/lib/httpd/modules/mod_gridsite.so -LoadModule mime_module /usr/lib/httpd/modules/mod_mime.so -LoadModule dir_module /usr/lib/httpd/modules/mod_dir.so - -TypesConfig /etc/mime.types - -# User and group who will own files created by Apache -User nobody -Group nobody - -DocumentRoot "/var/www/htdocs" - - - AllowOverride None - - -LogLevel debug -LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined - -CustomLog logs/httpd-gridsite-access combined -ErrorLog logs/httpd-gridsite-errors - -HostnameLookups On - -###################################################################### -# Plain unauthenticated HTTP on port 80 -###################################################################### - -Listen 80 - - - - GridSiteIndexes on - GridSiteAuth on - GridSiteDNlists /etc/grid-security/dn-lists/ - - - - -###################################################################### -# Secured and possibly authenticated HTTPS on port 443 -###################################################################### -Listen 443 - - -SSLEngine on -SSLCertificateFile /etc/grid-security/hostcert.pem -SSLCertificateKeyFile /etc/grid-security/hostkey.pem -SSLCACertificatePath /etc/grid-security/certificates -#SSLCARevocationPath YOUR CRL DIRECTORY WOULD GO HERE -SSLSessionCache dbm:/var/cache/mod_ssl/scache -SSLSessionCacheTimeout 300 -SSLVerifyClient optional -SSLVerifyDepth 10 -SSLOptions +ExportCertData +StdEnvVars - - - GridSiteIndexes on - GridSiteAuth on - GridSiteDNlists /etc/grid-security/dn-lists/ - GridSiteGSIProxyLimit 0 -# GridSiteMethods GET PUT DELETE - - - diff --git a/org.gridsite.core/doc/httpd-webserver.conf b/org.gridsite.core/doc/httpd-webserver.conf deleted file mode 100644 index da332a0..0000000 --- a/org.gridsite.core/doc/httpd-webserver.conf +++ /dev/null @@ -1,219 +0,0 @@ -############################################################################## -## GridSite httpd-webserver.conf - Andrew McNab -## -## Example configuration file for GridSite as a Web Server -## (that is, primarily for interactive use with a browser.) -## -## For GridSite documentation, see http://www.gridsite.org/ -## -## This file should be renamed /etc/httpd/conf/httpd.conf and Apache -## restarted to use Apache2/GridSite as a webserver. -## -## You do not need to install the GridSite mod_ssl.so module if you -## do not wish to use Globus Proxies or VOMS attributes, but you must -## have the mod_gridsite.so in /usr/lib/httpd/modules -## -## We're assuming you have (a) the host's hostcert.pem and hostkey.pem -## in /etc/grid-security/ and (b) the Certification Authorities' you -## trust have their root certs in /etc/grid-security/certificates -## -## (You can get RPMs for many European and North American Grid CAs -## from https://datagrid.in2p3.fr/distribution/datagrid/security/ ) -## -## If you want to use DN Lists in ACLs, they should be placed/downloaded -## in /etc/grid-security/dn-lists/ or /var/www/htdocs/dn-lists/ -## (Lists in /etc/grid-security/dn-lists/ override lists elsewhere.) -## -## To start serving files, make a directory /var/www/htdocs owned by -## nobody.nobody, including the file .gacl containing: -## -## -## -## -## -## -## -## -## To enable writing, add DN List, Person or VOMS entries to the GACL -## (see the GridSite GACL document for the syntax.) For example: -## -## -## -## -## -## -## -## -## /C=UK/O=eScience/OU=Manchester/L=HEP/CN=Andrew McNab -## -## -## -## -## -## and add the following directive to the HTTPS section: -## -## GridSiteMethods GET PUT DELETE -## -## If you wish to accept Globus GSI Proxies as well as full X.509 user -## certificates, set GridSiteGSIProxyLimit to the depth of proxy you -## wish to accept. -## -## (As a _rough_ guide: 0=No Proxies; 1=Proxy on user's machine; 2=Proxy -## owned by running Globus job; 3=Proxy delegated by a Globus job.) -## -## With this done and Apache restarted, you can upload a file with: -## -## curl -v --cert ~/.globus/usercert.pem --key ~/.globus/userkey.pem \ -## --capath /etc/grid-security/certificates --upload-file /tmp/tmp.txt \ -## https://INSERT.HOSTNAME.HERE/tmp.txt -## -## (or with --cert /tmp/x509up_u`id -u` --key /tmp/x509up_u`id -u` to use -## a Globus GSI Proxy created with grid-proxy-init.) -############################################################################## - -ServerRoot "/etc/httpd" - -## You MUST put your server's fully qualified domain name here -## This, the DOMAIN part of the https://DOMAIN/... URLs you want -ServerName FULL.SERVER.NAME - -PidFile logs/httpd.pid - -Timeout 300 -KeepAlive On -MaxKeepAliveRequests 100 -KeepAliveTimeout 15 - -LoadModule log_config_module /usr/lib/httpd/modules/mod_log_config.so -LoadModule ssl_module /usr/lib/httpd/modules/mod_ssl.so -LoadModule gridsite_module /usr/lib/httpd/modules/mod_gridsite.so -LoadModule mime_module /usr/lib/httpd/modules/mod_mime.so -LoadModule dir_module /usr/lib/httpd/modules/mod_dir.so -LoadModule alias_module /usr/lib/httpd/modules/mod_alias.so -LoadModule cgi_module /usr/lib/httpd/modules/mod_cgi.so - -TypesConfig /etc/mime.types - -# User and group who will own files created by Apache -User nobody -Group nobody - -DocumentRoot "/var/www/htdocs" - - - AllowOverride None - - -LogLevel debug -LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined - -CustomLog logs/httpd-gridsite-access combined -ErrorLog logs/httpd-gridsite-errors - -HostnameLookups On - -###################################################################### -# Plain unauthenticated HTTP on port 80 -###################################################################### - -Listen 80 - - -## This is used to serve the Manage Directory links in footers, -## and to allow you to edit files and ACLs via your browser. -ScriptAlias /real-gridsite-admin.cgi /usr/sbin/real-gridsite-admin.cgi - - - ## This sets up GACL authorization for this server. - GridSiteAuth on - - ## This exports various bits of info into the CGI environment - ## variables (and is needed for gridsite-admin.cgi to work.) - GridSiteEnvs on - - ## Nice GridSite directory listings (without truncating file names!) - GridSiteIndexes on - - ## If this is on, GridSite will look for gridsitehead.txt and - ## gridsitefoot.txt in the current directory or its parents, and - ## use them to replace the and tags in .html files. - GridSiteHtmlFormat on - - ## These directives (and the ScriptAlias above) allow authorized - ## people to manage files, ACLs and DN Lists through their web - ## browsers. Via HTTP, this just means extended directory listings - ## and History pages. - GridSiteAdminURI /real-gridsite-admin.cgi - GridSiteAdminFile gridsite-admin.cgi - - - - -###################################################################### -# Secured and possibly authenticated HTTPS on port 443 -###################################################################### -Listen 443 - - -SSLEngine on -SSLCertificateFile /etc/grid-security/hostcert.pem -SSLCertificateKeyFile /etc/grid-security/hostkey.pem -SSLCACertificatePath /etc/grid-security/certificates -#SSLCARevocationPath YOUR CRL DIRECTORY WOULD GO HERE -SSLSessionCache dbm:/var/cache/mod_ssl/scache -SSLSessionCacheTimeout 300 -SSLVerifyClient optional -SSLVerifyDepth 10 -SSLOptions +ExportCertData +StdEnvVars - -## This is used to serve the Manage Directory links in footers, -## and to allow you to edit files and ACLs via your browser. -ScriptAlias /real-gridsite-admin.cgi /usr/sbin/real-gridsite-admin.cgi - - - ## This sets up GACL authorization for this server. - GridSiteAuth on - - ## This exports various bits of info into the CGI environment - ## variables (and is needed for gridsite-admin.cgi to work.) - GridSiteEnvs on - - ## Nice GridSite directory listings (without truncating file names!) - GridSiteIndexes on - - ## If this is on, GridSite will look for gridsitehead.txt and - ## gridsitefoot.txt in the current directory or its parents, and - ## use them to replace the and tags in .html files. - GridSiteHtmlFormat on - - ## This is the path of directories (and all their subdirectories) for - ## GACL to search when it encounters a dn-list credential. The DN List - ## files are plain text, one DN per line, and must have the full url - ## as the file name, but URL Encoded - eg with urlencode(1) - GridSiteDNlists /etc/grid-security/dn-lists/:/var/www/htdocs/dn-lists/ - - ## This is used to form the URL at which DN Lists "owned" by this - ## server are exported. https://FULL.SERVER.NAME/dn-lists/file - ## ALL FILES WITH URLs ON THIS SERVER WILL BE EXPORTED IRRESPECTIVE - ## OF WHERE THEY ARE FOUND ON THE DN-LISTS PATH!! - GridSiteDNlistsURI /dn-lists/ - - ## If this is greater than zero, we will accept GSI Proxies for clients - ## (full client certificates - eg inside web browsers - are always ok) - GridSiteGSIProxyLimit 0 - - ## This directive allows authorized people to write/delete files - ## from non-browser clients - eg with htcp(1) - GridSiteMethods GET PUT DELETE - - ## These directives (and the ScriptAlias above) allow authorized - ## people to manage files, ACLs and DN Lists through their web - ## browsers via HTTPS. The value of GridSiteAdminFile appears to - ## exist in every directory, but is internally redirected by - ## mod_gridsite to the value of GridSiteAdminURI (the ScriptAlias - ## then maps that onto the real-gridsite-admin.cgi executable.) - GridSiteAdminURI /real-gridsite-admin.cgi - GridSiteAdminFile gridsite-admin.cgi - - - diff --git a/org.gridsite.core/doc/index.html b/org.gridsite.core/doc/index.html deleted file mode 100644 index a93f2cb..0000000 --- a/org.gridsite.core/doc/index.html +++ /dev/null @@ -1,92 +0,0 @@ -GridSite 1.1.x Documentation - -

GridSite 1.1.x Documentation

- -

-GridSite -is a set of extensions to the Apache 2.0 webserver, which support -Grid security based on X.509 certificates. Since GridSite applies access -control within Apache itself, via mod_gridsite, Grid authorization and -the associated verified credentials are available to all technologies -supported by Apache, including static file serving, SSI, CGI, PHP, JSP and -mod_perl. - -

Guides

- -

-

-
User Guide -
End-user documentation for people managing webpages and files on - GridSite servers, either through the web interface or with command - line clients like htcp. -

- -

Admin Guide -
For people administering areas of GridSite websites or fileservers, or - managing GridSite's support for DN List groups. -

- -

Building and Installation -
Instructions for building GridSite from source, and installing from - binaries or RPMs. -

- -

Config Guide -
For webmasters setting up Apache 2.0 and GridSite, and writing the - Apache httpd.conf file. -

- -

httpd-fileserver.conf and - httpd-webserver.conf -
Example configuration files for simple HTTP(S) fileservers and - webservers, with explanatory comments. -

- -

- -

Reference

- -

-

-
Grid Access Control Lists -
Syntax and usage of the XML Grid Access Control Lists used by GridSite. -

- -

htcp and - urlencode man pages -
Command line tools for copying files to or from HTTP(S) servers, and - for URL-encoding strings. -

- - - -

mod_gridsite -
An Apache 2.0 module which enforces access control via Grid Access - Control Lists, and X.509, GSI or VOMS credentials. mod_gridsite also - gives Apache built-in support for the HTTP PUT and DELETE methods, and - formatting of HTML pages with standard headers and footers. -

- - - -

gridsite.h API reference -
A detailed description of the C API provided by libgridsite, generated - from the sources by doxygen. -

- -

- - diff --git a/org.gridsite.core/doc/install.html b/org.gridsite.core/doc/install.html deleted file mode 100644 index 91a60d2..0000000 --- a/org.gridsite.core/doc/install.html +++ /dev/null @@ -1,148 +0,0 @@ -GridSite: Building and Installation Guide - -

GridSite: Building and Installation Guide

- -

-This Guide explains how to build GridSite from source, and how to install -the server components alongside an Apache 2.0 webserver. There is a -separate Config Guide which explains how to modify -the httpd.conf file, and how to set up other files and directories used by -the system. You should look through all of this Building and Installation -Guide to decide which is the easiest route for your system. - -

Installing with RPM

- -

-If you are installing on Linux with the binary RPM release, you can skip -most of this Guide, install the binary rpm(s) and go straight -to the Config Guide. - -

-We currently distribute GridSite RPMs for RedHat Linux versions 9 and 7.3 -from our download area at - -https://www.gridsite.org/download/ - -

-RedHat 9: -This is the simpler case, since the standard release includes a suitable -version of Apache 2.0: just install the gridsite-...-1.i386.rpm to get the -various GridSite components. - -

-RedHat 7.3: -This is more complicated because you must also install a back-ported Apache -2.0 RPM. We distribute RPMs built on 7.3 aimed at RedHat 7.3 -machines with updates, from our download area. These are built from the -tar.gz and .spec files distributed by the -Apache Foundation itself, using the -build-apache2.sh script in the GridSite -/usr/share/doc/gridsite directory. The Apache RPMs install in /usr, and you -should at least install the httpd and mod_ssl RPMs. -You must also install the gridsite-...-1.i386.rpm as above. - -

-GridSite also depends on shared libraries from libcurl and libxml2, and the -RPMs distributed as part of the standard RedHat 7.3 and 9 releases are -sufficient. - -

-With the RPMs installed, you can proceed to the -Config Guide. - -

Requirements for building GridSite from source

- -

-GridSite is currently only supported on Linux, but should be -straightforwardly -portable to other Unix platforms where the GNU build tools are available. - -

-GridSite consists of a core library (libgridsite[.so|.a]), an Apache module -(mod_gridsite.so), a CGI utility (gridsite-admin.cgi) and some command line -tools (htcp, urlencode.) - -

-All of the components use the GridSite library, and this in turn depends on -libcurl and libxml2. You will need the development versions of these -packages installed before you can proceed. (They are available as part of -RedHat Linux releases 7.x onwards, for instance.) - -

Building GridSite with Make

- -

-Our download area at - -https://www.gridsite.org/download/ includes a tar-ball -distribution of the sources, which can be unpacked and used to build -GridSite from source. (Bleeding-edge developers can get the current snapshot -of the same files from our CVS area.) - -

-GridSite needs a copy of the Apache 2.0 include files to build, and the -location of this is set by the MYCFLAGS variable in the top-level Makefile. -For manual builds, the default -MYCFLAGS=-I/usr/local/include/httpd is used. -If you wish to use the GridSite module with Apache -2.0 installed elsewhere, you should change the MYCFLAGS variable to point to -the includes directory installed by the development part of that Apache 2.0 -distribution. - -

-

-make 
-make install
-
- -

-will build all components and install them all under the default -locations of /usr/local/[lib|bin|include|sbin] The default prefix for manual -builds is -/usr/local, as set by the prefix variable in the top level Makefile -(/usr is the default for RPMs.) - -

Building GridSite with RPM

- -

-For RedHat Linux and derivatives, building with RPM is recommended. -The command make rpm in the top level of the source tree -will build the GridSite and htcp binary RPMs in the -directory ../RPMTMP/RPMS/i386 relative to the working directory. An SRPM is -put into ../RPMTMP/SRPMS -This build assumes the Apache 2.0 includes are in /usr/include/httpd. - -

-If you make RPMs on a RedHat 9 system (or a 7.3 system with our httpd RPM -installed), you can install the resulting GridSite -RPM alongside the standard Apache 2.0 RPM without having to -modify shared library or Apache module paths. - -

-For other configurations, -you can modify the assumed location of the Apache 2.0 includes -by changing the MYCFLAGS variable in the rpm target near the -foot of the top level Makefile. - -

Building Apache 2.0

- -

-If it is not possible to use binary RPMs of Apache 2.0, -then it can be built from source using the build-apache2.sh script -found in the GridSite docs directory. -The script includes instructions on how to build from the tarballs -distributed by the Apache Foundation. -(it removes the -C option from "configure -C" in the .spec file -and builds the RPMs under the current directory.) - -

-If these targets do not work on your build platform, -the Makefile and the scriptlets in the included SPEC files are a good -starting point for building Apache by hand yourself. The complexities of -this are outside of the scope of this Guide, but you are welcome to ask for -assistance on the -GridSite -Discussion List, although -www.apache.org is a better starting -point for purely Apache problems. - - diff --git a/org.gridsite.core/doc/library.html b/org.gridsite.core/doc/library.html deleted file mode 100644 index 28458ae..0000000 --- a/org.gridsite.core/doc/library.html +++ /dev/null @@ -1 +0,0 @@ -library docs diff --git a/org.gridsite.core/doc/module.html b/org.gridsite.core/doc/module.html deleted file mode 100644 index 7f2096e..0000000 --- a/org.gridsite.core/doc/module.html +++ /dev/null @@ -1,271 +0,0 @@ -GridSite Apache module: mod_gridsite - -

GridSite Apache module: mod_gridsite

- -

-mod_gridsite is an Apache 2.0 module which enforces access control via Grid -Access Control Lists, and X.509, GSI or VOMS credentials. mod_gridsite also -gives Apache built-in support for the HTTP PUT and DELETE methods, and -formatting of HTML pages with standard headers and footers. - -

-Since mod_gridsite access -control within Apache itself, Grid authorization and -the associated verified credentials are available to all technologies -supported by Apache, including static file serving, SSI, CGI, PHP, mod_perl -and Java servlets via a connector to Tomcat. - -

-Operation of mod_gridsite can be configured using runtime directives -in Apache's standard httpd.conf configuration file. The module must first be -loaded with a LoadModule directive: - -

-LoadModule gridsite_module /PATH/TO/MODULES/mod_gridsite.so - -

-The module's behaviour is then controlled by GridSite... directives within -Apache <Directory ...> sections, allowing different directories to use -GridSite features in different ways. - -

GridSite directives

- -
-
GridSiteIndexes on|off -
Determines whether GridSite generates HTML directory listings. These - have some advantages over standard Apache directory listings (eg the - displayed filenames are never truncated) and will include standard - headers and footers if GridSiteHtmlFormat is on. -
- (Default: GridSiteIndexes off) -

- -

GridSiteIndexHeader file -
If the named file is found in the directory being listed, the file - is included verbatim at the top of the listing and excluded from - the file-by-file listing. The file can either be HTML or plain text (in - which case browsers will be treat it as one HTML paragraph.) -
- (Default: none) -

- -

GridSiteHtmlFormat on|off -
Determines where HTML pages receive additional formatting before being - sent to the client. This includes the "Last modified", - "View page history", "Switch to HTTP(S)", - "Print View" and "Built with GridSite" footer - elements. If header and footer files are found, they will be used too. -
- (Default: GridSiteHtmlFormat off) -

- -

GridSiteHeadFile file
- GridSiteFootFile file -
Set the filenames to be searched for as standard headers and footers - for HTML pages. For each HTML page, the directory of that page is tried - first, and then parent directories in ascending order until a header / - footer file is found. Header files are inserted in place of HTML - <body[ ...]> tags; footer files in place of </body>. (These - standard files should each include the appropriate body tag as a - replacement.) -
- (Defaults: GridSiteHeadFile gridsitehead.txt, - GridSiteFootFile gridsitefoot.txt) -

- -

GridSiteAuth on|off -
Enables GridSite access control features, using - GACL files. The files are named .gacl and are - per-directory. The current directory is tried and then parent - directories in ascending order until a .gacl file is found. -
- (Default: GridSiteAuth off) -

- -

GridSiteAdminList uri -
All members of the DN List with name "uri" receive the full set - of permissions, irrespective of per-directory .gacl files. People in - this group have full control over the whole site. -
- (Default: none) -

- -

GridSiteGSIProxyLimit limit -
When using GSI Proxy credentials, - proxies with delegation depth greater than "limit" will - be ignored by mod_gridsite authorization decisions. A limit of zero - implies only full X.509 - certificates (and no proxies) will be accepted. A limit of 1 implies - that only the initial proxy, usually created on the user's own machine, - is acceptable. Higher levels lead to proxies on remote machines, eg - used by running jobs, being accepted. -
- (Default: GridSiteGSIProxyLimit 1) -

- -

GridSiteMethods [GET] [PUT] [DELETE] -
Specifies which HTTP methods are supported by GridSite. GET (and HEAD) - are always supported. PUT and DELETE support is turned on by this - directive, subject to a positive statement that write permission is - allowed for the directory in question, by a GACL file. -
- (Default: GridSite GET) -

- -

GridSiteDNlists directory1[:directory2[:directory3]...] -
Sets up the DN List path used by GACL for - evaluating <dn-list> credentials. If this directive is not used, - then GACL will use the GRST_DN_LISTS variable from Apache's own - environment. If that is not set either, then /etc/grid-security/dn-lists - is searched. -
- (Default: none) -

- -

GridSiteDNlistsURI uri -
If GridSiteDNlistsURI is used, then the URI given appears to be - populated with all the DN lists on the current DN lists path which - match the current server. That is, for server https://example.org/ - with DN lists URI /dn-lists/, all DN lists with URLs starting - https://example.org/dn-lists/ will appear to be present in /dn-lists/, - irrespective of where in the path they are stored. -
- (Default: none) -

- -

GridSiteAdminURI uri -
GridSiteAdminURI gives the absolute URI on the server of the GridSite - Admin CGI program, which is used for file management, HTML and GACL - editing. This should be used in conjunction with the standard Apache - directive ScriptAlias to map that URI to the real-gridsite-admin.cgi - executable. For example: -
- ScriptAlias /real-gridsite-admin.cgi - /PATH/TO/real-gridsite-admin.cgi -
- This URI is always reached by an internal redirection from the value - set by GridSiteAdminFile, and is never visible to users. -
- (Default: none) -

- -

GridSiteAdminFile cgifilename -
If GridSiteAdminURI is set, then the cgifilename of GridSiteAdminFile - appears to be present in all directories when explicitly - requested (it does not appear in directory listings.) Requests for these - ghost CGI URIs are internally redirected to the value set by - GridSiteAdminURI. -
- (Default: GridSiteAdminFile gridsite-admin.cgi) -

- -

GridSiteEnvs on|off -
This makes mod_gridsite export several variables into the environment - of CGI programs and other dynamic content systems. The variable names - are listed below. For gridsite-admin.cgi mechanism to work, this switch - must be left in its default state of on. -
- (Default: GridSiteEnvs on) -

- -

GridSiteEditable [ext1 [ext2 [ext3] ...]]] -
A space-separated list of file extensions which can safely be edited - by the GridSite Text/HTML editor. The extensions are given without the - initial dot. -
- (Default: GridSiteEditable txt shtml html htm css js php jsp) -

- -

GridSiteHelpURI uri -
If set, gives the URI to use for "Website Help" links in HTML - page footers. -
- (Default: none) -

- -

GridSiteLink on|off -
Turns off the link in the HTML page footers which gives credit to - GridSite. -
- (Default: GridSiteLink on) -

- -

GridSiteUnzip path -
If "path" is set by this directive, then real-gridsite-admin.cgi - will offer to list the contents of .zip archives on the server. - Users with write access are able to unpack the contents into the same - directory as the .zip file. The value of "path" must point - to the location of the - unzip binary. -
- (Default: none) -

- -

- -

Environment variables

- -

-The following variables are present in the environment of CGI programs and -other dynamic content systems if the GridSiteEnvs on directive is -in effect. - -

-

-
GRST_PERM -
Numerical value of the permission bit-map obtained by comparing the - user with the GACL in force. (These should be tested using the - GRSTgaclPermHasXXXX functions from GACL.) -

- -

GRST_ADMIN_LIST -
URI of the DN List, listing people with full admin and write access - to the whole site. -

- -

GRST_GSIPROXY_LIMIT -
Maximum valid delegation level for GSI Proxies. -

- -

GRST_DIR_PATH -
Absolute path in the local filesystem to the directory holding the - file being requested. -

- -

GRST_HELP_URI -
URI of website help pages set by GridSiteHelpURI directive. -

- -

GRST_ADMIN_FILE -
Filename of per-directory ghost gridsite-admin.cgi program. (This is - used by real-gridsite-admin.cgi to construct links in its pages.) -

- -

GRST_EDITABLE -
Space-separated list of extensions which can safely be edited with a - Text/HTML editor. -

- -

GRST_HEAD_FILE and GRST_FOOT_FILE -
Filenames of standard header and footer files. -

- -

GRST_DN_LISTS -
DN lists search path. -

- -

GRST_DN_LISTS_URI -
Directory of virtual URIs used to publish this site's DN Lists. -

- -

GRST_UNZIP -
Full path to the unzip binary, used to list and unpack .zip files. -

- -

GRST_NO_LINK -
If set, do not include credit links to GridSite in page footers. -

- -

- - diff --git a/org.gridsite.core/doc/urlencode.1 b/org.gridsite.core/doc/urlencode.1 deleted file mode 100644 index fe84405..0000000 --- a/org.gridsite.core/doc/urlencode.1 +++ /dev/null @@ -1,46 +0,0 @@ -.TH urlencode 1 "November 2003" urlencode "URLENCODE Manual" -.SH NAME -.B urlencode -\- convert strings to or from URL-encoded form -.SH SYNOPSIS -.B urlencode -[-m|-d] -.I string [string ...] -.SH DESCRIPTION -.B urlencode -encodes strings according to RFC 1738. - -That is, characters A-Z a-z 0-9 . _ -and - are passed through unmodified, but all other characters are -represented as %HH, where HH is their two-digit upper-case hexadecimal ASCII -representation. -For example, the URL http://www.gridpp.ac.uk/ becomes -http%3A%2F%2Fwww.gridpp.ac.uk%2F - -.B urlencode -converts each character in all the strings given on the command line. If -multiple strings are given, they are concatenated with separating spaces -before conversion. - -.SH OPTIONS -.IP "-m" -Instead of full conversion, do GridSite "mild URL encoding" in which A-Z a-z -0-9 . = - _ @ and / are passed through unmodified. This results in slightly -more human-readable strings but the application must be prepared to create -or simulate the directories implied by any slashes. - -.IP "-d" -Do URL-decoding rather than encoding, according to RFC 1738. %HH and %hh -strings are converted and other characters are passed through unmodified, -with the exception that + is converted to space. - -.SH EXIT CODES -0 is always returned. - -.SH BUGS -Not enough beta testing (hint hint...) - -.SH AUTHOR -Andrew McNab - -urlencode is part of GridSite: http://www.gridsite.org/ diff --git a/org.gridsite.core/doc/user.html b/org.gridsite.core/doc/user.html deleted file mode 100644 index ae37cdd..0000000 --- a/org.gridsite.core/doc/user.html +++ /dev/null @@ -1,302 +0,0 @@ -GridSite User Guide - -

GridSite User Guide

- -

If you are setting up a GridSite-based website you may wish to use this -file as the basis of your end-user documentation. If so, copy all of the -files from the GridSite doc directory (probably -/usr/share/doc/gridsite-VERSION/) -to somewhere on your website like -/gridsite-doc/ and add GridSiteHelpURI /gridsite-doc/user.html -to the virtual server configuration in -httpd.conf - you should also look through the rest of the HTML source since -there are some comments you may find helpful. - -

-This Guide is intended for people using GridSite websites with conventional -web browsers, especially people with write access to areas of the site. - There is a separate -Administration Guide - with additional information for people managing access control and group -membership. This Guide assumes you are familiar with basic Web and HTML -concepts. Towards the end we discuss how to access servers with command -line tools like curl and htcp. - -

Reading from HTTP and HTTPS servers

- -

-GridSite servers are usually accessible both via HTTP and via HTTPS. You can -always tell which version you are using by looking at whether the URL in your -browser's location window starts with "http://" or -"https://" HTTPS means that the connection to the server is -encrypted, that you can verify you're talking to the real server and not an -imposter, and gives you the option to authenticate to the site and perhaps -gain write access. - -

- Simple browsing of the website via HTTP or HTTPS is reasonably - self-explanatory. If configured, additional links may appear in the footer - of each webpage with links to this help, - - and to switch between HTTP and HTTPS versions of the page. Pages may also - have a link to the page History, - - showing the dates of changes to that page and names of its authors. - -

- When looking at HTTPS pages, you may find your browser reports it cannot - verify the server's certificate since it does not recognise the - Certification Authority (CA) it uses. You should attempt to load the CA's - root certificate into your browser to stop these warnings. (This means your - browser will be able to identify any servers using fake certificates which - you shouldn't trust.) How you obtain the CA Root Certificate from a - trust-worthy source depends on the CA. For example, the UK e-Science CA - lets you download it from their - website. - - -

Authenticating

- -

- To go beyond reading pages you need to obtain a user certificate and load it - into your web browser. How you do this again depends on the Certification - Authority you have access to (for most Grid projects, CAs are organised - on a national basis.) To use the UK e-Science CA example again, - from their website has links to - the procedure for applying for a certificate from within a web browser. - - -

-A user certificate usually has a version of your name and affiliation as its -Distinguished Name (DN) - for example, -"/C=UK/O=eScience/OU=Manchester/L=HEP/CN=Andrew McNab" - -

-Once you've obtained a user certificate in your name from your CA, you need -to make sure it is loaded into the browser you normally use to browse the -web. How you do this is different for different browsers and to some extent -for different CAs (but if you applied -for the CA through your browser, you may already have it there.) - -

-Browsers want the certificate and private key in the PKCS#12 format, which -is normally a single file with the extension ".p12". -Many programs which are based on OpenSSL, such as Globus and curl, prefer -the PEM (".pem") format for certificates, with separate -certificate and key files ("usercert.pem" and -"userkey.pem", for example.) If you only have the files in .pem -format and have access to openssl, you -can use its command line tools to convert PEM to PKCS#12: -

-openssl pkcs12 -in usercert.pem -inkey userkey.pem -export -out certkey.p12
-
- -

-Be very careful not to accidentally overwrite .pem or .p12 files when -doing this kind of thing! In particular, if you lose your private key, you -cannot retrieve it from your CA. - -

- Once your user certificate is loaded, you should be able to see your - certificate name appear when you look at an HTTPS GridSite page which has - the page footers enabled - for example, the "Switch to HTTP" link - present. If GridSite understands your user certificate, it displays a - "You are ..." line in the footer. (However, the Apache webserver - must also be set up with your CAs root certificate for this to work. The - GridPP HTTPS home page is set up - to recognise a good range of European and North American Grid CAs.) - - -

Authorization

- -

- Once users can prove their identity to the web server, it then becomes - possible to give them appropriate rights depending on that identity. - GridSite allows site administrators to specify these rights for individuals - and groups using -GACL - access control files. (The -Administration Guide - explains how to manage these files.) GACL defines who can - read files, who can list directories, - who can write or create files and who can modify the GACL policy files. To - get increased access to an area of a site, you need to contact the - administrator for that area and give the DN of your certificate (it's not - necessary to send any certificate files.) - -

Managing Directories and Files

- -

-If you have list permission for the directory containing a page, you should -see an extra link "Manage Directory" in the page's set of footer -links, which allows you to browse the directory even if the normal -index.html is present. If page histories are available, this listing view -also has links to them. - -

-The real power of GridSite becomes available if you have write access to a -directory. In that case, the "Manage Directory" page has -additional links to Delete or Rename pages and other files, and to Edit HTML -and plain text files. An Edit link also appears in the footer links of HTML -pages. - -

-If you use the Edit function, you are presented with an HTML form containing -the current filename and the full HTML or plain text of the page for you to -edit. This allows you to maintain the content of the site "in -place" and to see the result of your changes immediately, in context. - -

-If you modify the filename in the form before saving, GridSite will make a -new file with that name, and the old file will still be present, unmodified. -(However, you cannot use this feature for creating a file in a different -directory.) -As you make changes, the history of the changes and your certificate DN are -recorded, and available in the history page for that file. - -

- For people with write access, the "Manage Directory" page also has - options to upload a file from the computer your browser is running on, and to - create files and directories. If it's enabled, you can also view the - contents of WinZIP / PKZIP / .zip files, and unpack their contents into the - current directory. (This feature is very useful if you have several files - to upload at one time.) - - -

HTML Formatting in GridSite

- -

-As well as providing access control and file management, GridSite provides -some simple formatting of HTML pages by adding standard headers and footers. -(If this isn't sufficient, GridSite will happily coexist with HTML -preprocessor languages like SSI, PHP and JSP.) - -

- If HTML formatting is enabled - for the current directory, GridSite looks for the files gridsitehead.txt and - gridsitefoot.txt in that directory, or goes up through the parent - directories until they are found. - - -

-The <body> and </body> tags from the HTML file are replaced with -the contents of the gridsitehead.txt and gridsitefoot.txt files, which -should normally be chunks of HTML including a replacement <body> -or </body> tag. If either tag is absent from the original page, then -the header or footer is just added rather than being inserted in place of -the tag. (One consequence of this absence is that HTML header tags like -<title> can end up after a <body> tag, and can get ignored by -browsers - so always include <body> ... </body> in your pages.) - -

-This simple system is suprisingly flexible, and allows a variety of top and -bottom, or sidebar navigation layouts of pages. Since the <body ...> -tag is under full control of the author of the gridsitehead.txt file, -backgrounds, colour schemes and style sheets can easily be specified. - -

-For example: - -

- - - - - - - - - -
SourceHTML
page.html<title>PAGE TITLE</title>
page.html
(replaced)
<body>
gridsitehead.txt<body text=blue>
- Heading text
- <table border=1>
<tr>
<td>Standard<br>
- sidebar</td>
<td>
page.html<p>
Page content...
page.html
(replaced)
</body>
gridsitefoot.txt</td>
</tr>
- </table>
Footer text
</body>
- -

-produces pages with a layout like: - -

- - - - -
Heading text
Standard
sidebar
Page content...
Footer text
- -

Command line use

- -

-GridSite adds support for the HTTP PUT and DELETE methods, and this makes it -easy to create or delete files from within programs and commands without -using a web browser and HTML forms. It is straightforward, although slightly -awkward, to use a standard HTTPS-aware client like -curl to upload files, but GridSite -provides htcp as a more convenient client program, which is easier to use -with GSI Proxies and X.509 user certificates, and has a syntax closer to the -familiar scp command. - -

-The following examples assume the GridSite server has GSI support and use a -GSI proxy as the client certificate. For non-GSI use, just skip the -grid-proxy-init stage, and replace the proxy -filename with $HOME/.globus/usercert.pem and $HOME/.globus/userkey.pem (or -wherever your PEM format certificate and key are stored.) - -

-First generate a GSI proxy with grid-proxy-init. This will create a proxy file -in /tmp/x509up_uXXXXX where XXXXX is your Unix UID (also given by id --u.) The GSI proxy contains a -temporary private key and certificate signed by your long-term user -certificate. - -

-You should make sure you have a copy of the CA root certificates of the CA's -used by the servers you wish to talk to. These are usually installed in -/etc/grid-security/certificates as files like 01621954.0, and RPMs and tar -files for many common European and North American CAs are available from - -https://datagrid.in2p3.fr/distribution/datagrid/security/ - -

-To upload a file with curl: -

-curl --cert /tmp/x509up_u`id -n` --key /tmp/x509up_u`id -n` \
-     --capath /etc/grid-security/certificates \
-     --upload-file /tmp/new.file.txt https://server/new.file.txt
-
- -

-The equivalent htcp command is: -

-htcp /tmp/new.file.txt https://server/new.file.txt
-
-since htcp looks for the GSI proxy and CA certificates automatically. htcp -can also be used to copy remote files to the local machine by reversing the -arguments. For more details, see the -htcp(1) man page. - -

-htcp also has options for deleting files, and doing short or long listings, -and these can also be accessed using the htrm, htls and htll commands (which -are normally symbolic links to htcp.) - -

-Directory indexes are based on parsing the index returned by the web server -and by using the HTTP HEAD method to obtain the file size and modification -times. - -

-All of the ht** commands can accept multiple source file arguments, and this -allows you to copy multiple files to or from the server. Shell wildcard -expansion on the local machine is especially useful: -

-htcp /tmp/new.*.txt https://server/
-
- - diff --git a/org.gridsite.core/interface/gridsite-gacl.h b/org.gridsite.core/interface/gridsite-gacl.h deleted file mode 100644 index f739c00..0000000 --- a/org.gridsite.core/interface/gridsite-gacl.h +++ /dev/null @@ -1,188 +0,0 @@ -/* - Copyright (c) 2002-4, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/*---------------------------------------------------------------* - * For more about GridSite: http://www.gridsite.org/ * - *---------------------------------------------------------------*/ - -#ifndef HEADER_GACL_H -#define HEADER_GACL_H -#endif - -#ifndef GACL_LIB_VERSION -#define GACL_LIB_VERSION "x.x.x" -#endif - -typedef GRSTgaclCred GACLcred; - -typedef int GACLaction; -typedef unsigned int GACLperm; - -typedef GRSTgaclEntry GACLentry; - -typedef GRSTgaclAcl GACLacl; - -typedef GRSTgaclUser GACLuser; - -extern char *gacl_perm_syms[]; -extern GACLperm gacl_perm_vals[]; - -#define GACL_PERM_NONE GRST_PERM_NONE -#define GACL_PERM_READ GRST_PERM_READ -#define GACL_PERM_LIST GRST_PERM_LIST -#define GACL_PERM_WRITE GRST_PERM_WRITE -#define GACL_PERM_ADMIN GRST_PERM_ADMIN - -#define GACLhasNone(perm) (perm == 0) -#define GACLhasRead(perm) ((perm & GRST_PERM_READ) != 0) -#define GACLhasList(perm) ((perm & GRST_PERM_LIST) != 0) -#define GACLhasWrite(perm) ((perm & GRST_PERM_WRITE) != 0) -#define GACLhasAdmin(perm) ((perm & GRST_PERM_ADMIN) != 0) - -#define GACL_ACTION_ALLOW GRST_ACTION_ALLOW -#define GACL_ACTION_DENY GRST_ACTION_DENY - -#define GACL_ACL_FILE GRST_ACL_FILE -#define GACL_DN_LISTS GRST_DN_LISTS - -#define GACLinit() GRSTgaclInit() - -#define GACLnewCred(x) GRSTgaclCredNew((x)) -/* GACLcred *GACLnewCred(char *); */ - -#define GACLaddToCred(x,y,z) GRSTgaclCredAddValue((x),(y),(z)) -/* int GACLaddToCred(GACLcred *, char *, char *); */ - -#define GACLfreeCred(x) GRSTgaclCredFree((x)) -/* int GACLfreeCred(GACLcred *); */ - -#define GACLaddCred(x,y) GRSTgaclEntryAddCred((x),(y)) -/* int GACLaddCred(GACLentry *, GACLcred *); */ - -#define GACLdelCred(x,y) GRSTgaclEntryDelCred((x),(y)) -/* int GACLdelCred(GACLentry *, GACLcred *); */ - -#define GACLprintCred(x,y) GRSTgaclCredPrint((x),(y)) -/* int GACLprintCred(GACLcred *, FILE *); */ - - -#define GACLnewEntry() GRSTgaclEntryNew() -/* GACLentry *GACLnewEntry(void); */ - -#define GACLfreeEntry(x) GRSTgaclEntryFree((x)) -/* int GACLfreeEntry(GACLentry *); */ - -#define GACLaddEntry(x,y) GRSTgaclAclAddEntry((x),(y)) -/* int GACLaddEntry(GACLacl *, GACLentry *); */ - -#define GACLprintEntry(x,y) GRSTgaclEntryPrint((x),(y)) -/* int GACLprintEntry(GACLentry *, FILE *); */ - - -#define GACLprintPerm(x,y) GRSTgaclPermPrint((x),(y)) -/* int GACLprintPerm(GACLperm, FILE *); */ - -#define GACLallowPerm(x,y) GRSTgaclEntryAllowPerm((x),(y)) -/* int GACLallowPerm(GACLentry *, GACLperm); */ - -#define GACLunallowPerm(x,y) GRSTgaclEntryUnallowPerm((x),(y)) -/* int GACLunallowPerm(GACLentry *, GACLperm); */ - -#define GACLdenyPerm(x,y) GRSTgaclEntryDenyPerm((x),(y)) -/* int GACLdenyPerm(GACLentry *, GACLperm); */ - -#define GACLundenyPerm(x,y) GRSTgaclEntryUndenyPerm((x),(y)) -/* int GACLundenyPerm(GACLentry *, GACLperm); */ - -#define GACLpermToChar(x) GRSTgaclPermToChar((x)) -/* char *GACLpermToChar(GACLperm); */ - -#define GACLcharToPerm(x) GRSTgaclPermFromChar((x)) -/* GACLperm GACLcharToPerm(char *); */ - -#define GACLnewAcl() GRSTgaclAclNew() -/* GACLacl *GACLnewAcl(void); */ - -#define GACLfreeAcl(x) GRSTgaclAclFree((x)) -/* int GACLfreeAcl(GACLacl *); */ - -#define GACLprintAcl(x,y) GRSTgaclAclPrint((x),(y)) -/* int GACLprintAcl(GACLacl *, FILE *); */ - -#define GACLsaveAcl(x,y) GRSTgaclAclSave((y),(x)) -/* int GACLsaveAcl(char *, GACLacl *); */ - -#define GACLloadAcl(x) GRSTgaclAclLoadFile((x)) -/* GACLacl *GACLloadAcl(char *); */ - -#define GACLfindAclForFile(x) GRSTgaclFileFindAclname((x)) -/* char *GACLfindAclForFile(char *); */ - -#define GACLloadAclForFile(x) GRSTgaclAclLoadforFile((x)) -/* GACLacl *GACLloadAclForFile(char *); */ - -#define GACLisAclFile(x) GRSTgaclFileIsAcl((x)) -/* int GACLisAclFile(char *); */ - - -#define GACLnewUser(x) GRSTgaclUserNew((x)) -/* GACLuser *GACLnewUser(GACLcred *); */ - -#define GACLfreeUser(x) GRSTgaclUserFree((x)) -/* int GACLfreeUser(GACLuser *); */ - -#define GACLuserAddCred(x,y) GRSTgaclUserAddCred((x),(y)) -/* int GACLuserAddCred(GACLuser *, GACLcred *); */ - -#define GACLuserHasCred(x,y) GRSTgaclUserHasCred((x),(y)) -/* int GACLuserHasCred(GACLuser *, GACLcred *); */ - -#define GACLuserFindCredType(x,y) GRSTgaclUserFindCredtype((x),(y)) -/* GACLcred *GACLuserFindCredType(GACLuser *, char *); */ - -#define GACLtestDnList(x,y) GRSTgaclDNlistHasUser((x),(y)) -/* int GACLtestDnList(char *, GACLuser *); */ - -#define GACLtestUserAcl(x,y) GRSTgaclAclTestUser((x),(y)) -/* GACLperm GACLtestUserAcl(GACLacl *, GACLuser *); */ - -#define GACLtestExclAcl(x,y) GRSTgaclAclTestexclUser((x),(y)) -/* GACLperm GACLtestExclAcl(GACLacl *, GACLuser *); */ - - -#define GACLurlEncode(x) GRSThttpUrlEncode((x)) -/* char *GACLurlEncode(char *); */ - -#define GACLmildUrlEncode(x) GRSThttpUrlMildencode((x)) -/* char *GACLmildUrlEncode(char *); */ - -GACLentry *GRSTgaclEntryParse(xmlNodePtr cur); -/* special function for legacy EDG LB service */ diff --git a/org.gridsite.core/interface/gridsite.h b/org.gridsite.core/interface/gridsite.h deleted file mode 100644 index febda2c..0000000 --- a/org.gridsite.core/interface/gridsite.h +++ /dev/null @@ -1,273 +0,0 @@ -/* - Copyright (c) 2002-3, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/*---------------------------------------------------------------* - * For more about GridSite: http://www.gridsite.org/ * - *---------------------------------------------------------------*/ - -#ifndef HEADER_SSL_H -#include -#endif - -#ifndef HEADER_CRYPTO_H -#include -#endif - -#ifndef FALSE -#define FALSE (0) -#endif -#ifndef TRUE -#define TRUE (!FALSE) -#endif - -/// Everything ok (= OpenSSL X509_V_OK) -#define GRST_RET_OK 0 - -/// Failed for unspecified reason -#define GRST_RET_FAILED 1000 - -/// Failed to find certificate in some cert store / directory -#define GRST_RET_CERT_NOT_FOUND 1001 - -/// Bad signature -#define GRST_RET_BAD_SIGNATURE 1002 - -/// No such file or directory -#define GRST_RET_NO_SUCH_FILE 1003 - -#define GRST_PROXYCERTINFO_OID "1.3.6.1.4.1.3536.1.222" -#define GRST_VOMS_OID "1.3.6.1.4.1.8005.100.100.1" -#define GRST_VOMS_DIR "/etc/grid-security/vomsdir" - - - -typedef struct { char *name; - char *value; - void *next; } GRSTgaclNamevalue; - -typedef struct { char *type; - int delegation; - GRSTgaclNamevalue *firstname; - void *next; } GRSTgaclCred; - -typedef int GRSTgaclAction; -typedef unsigned int GRSTgaclPerm; - -typedef struct { GRSTgaclCred *firstcred; - GRSTgaclPerm allowed; - GRSTgaclPerm denied; - void *next; } GRSTgaclEntry; - -typedef struct { GRSTgaclEntry *firstentry; } GRSTgaclAcl; - -typedef struct { GRSTgaclCred *firstcred; - char *dnlists; } GRSTgaclUser; - -#define GRST_PERM_NONE 0 -#define GRST_PERM_READ 1 -#define GRST_PERM_EXEC 2 -#define GRST_PERM_LIST 4 -#define GRST_PERM_WRITE 8 -#define GRST_PERM_ADMIN 16 -#define GRST_PERM_ALL 31 - -/* DO NOT USE PermIsNone!! */ -#define GRSTgaclPermIsNone(perm) (perm == 0) - -#define GRSTgaclPermHasNone(perm) (perm == 0) -#define GRSTgaclPermHasRead(perm) ((perm & GRST_PERM_READ ) != 0) -#define GRSTgaclPermHasExec(perm) ((perm & GRST_PERM_EXEC ) != 0) -#define GRSTgaclPermHasList(perm) ((perm & GRST_PERM_LIST ) != 0) -#define GRSTgaclPermHasWrite(perm) ((perm & GRST_PERM_WRITE) != 0) -#define GRSTgaclPermHasAdmin(perm) ((perm & GRST_PERM_ADMIN) != 0) - -#define GRST_ACTION_ALLOW 0 -#define GRST_ACTION_DENY 1 - -#define GRST_HIST_PREFIX ".grsthist" -#define GRST_ACL_FILE ".gacl" -#define GRST_DN_LISTS "/etc/grid-security/dn-lists" -#define GRST_RECURS_LIMIT 9 - -int GRSTgaclInit(void); - -/* #define GACLnewCred(x) GRSTgaclCredNew((x)) */ -GRSTgaclCred *GRSTgaclCredNew(char *); - -/* #define GACLaddToCred(x,y,z) GRSTgaclCredAddValue((x),(y),(z)) */ -int GRSTgaclCredAddValue(GRSTgaclCred *, char *, char *); - -#define GRSTgaclCredSetDelegation(cred, level) ((cred)->delegation = (level)) -#define GRSTgaclCredGetDelegation(cred) ((cred)->delegation) - -/* #define GACLfreeCred(x) GRSTgaclCredFree((x)) */ -int GRSTgaclCredFree(GRSTgaclCred *); - -/* #define GACLaddCred(x,y) GRSTgaclEntryAddCred((x),(y)) */ -int GRSTgaclEntryAddCred(GRSTgaclEntry *, GRSTgaclCred *); - -/* #define GACLdelCred(x,y) GRSTgaclEntryDelCred((x),(y)) */ -int GRSTgaclEntryDelCred(GRSTgaclEntry *, GRSTgaclCred *); - -/* #define GACLprintCred(x,y) GRSTgaclCredPrint((x),(y)) */ -int GRSTgaclCredCredPrint(GRSTgaclCred *, FILE *); - - -/* #define GACLnewEntry(x) GRSTgaclEntryNew((x)) */ -GRSTgaclEntry *GRSTgaclEntryNew(void); - -/* #define GACLfreeEntry(x) GRSTgaclEntryFree((x)) */ -int GRSTgaclEntryFree(GRSTgaclEntry *); - -/* #define GACLaddEntry(x,y) GRSTgaclAclAddEntry((x),(y)) */ -int GRSTgaclAclAddEntry(GRSTgaclAcl *, GRSTgaclEntry *); - -/* #define GACLprintEntry(x,y) GRSTgaclEntryPrint((x),(y)) */ -int GRSTgaclEntryPrint(GRSTgaclEntry *, FILE *); - - -/* #define GACLprintPerm(x,y) GRSTgaclPermPrint((x),(y)) */ -int GRSTgaclPermPrint(GRSTgaclPerm, FILE *); - -/* #define GACLallowPerm(x,y) GRSTgaclEntryAllowPerm((x),(y)) */ -int GRSTgaclEntryAllowPerm(GRSTgaclEntry *, GRSTgaclPerm); - -/* #define GACLunallowPerm(x,y) GRSTgaclEntryUnallowPerm((x),(y)) */ -int GRSTgaclEntryUnallowPerm(GRSTgaclEntry *, GRSTgaclPerm); - -/* #define GACLdenyPerm(x,y) GRSTgaclEntryDenyPerm((x),(y)) */ -int GRSTgaclEntryDenyPerm(GRSTgaclEntry *, GRSTgaclPerm); - -/* #define GACLundenyPerm(x,y) GRSTgaclEntryUndenyPerm((x),(y)) */ -int GRSTgaclUndenyPerm(GRSTgaclEntry *, GRSTgaclPerm); - -/* #define GACLpermToChar(x) GRSTgaclPermToChar((x)) */ -char *GRSTgaclPermToChar(GRSTgaclPerm); - -/* #define GACLcharToPerm(x) GRSTgaclPermFromChar((x)) */ -GRSTgaclPerm GRSTgaclPermFromChar(char *); - -/* #define GACLnewAcl(x) GRSTgaclAclNew((x)) */ -GRSTgaclAcl *GRSTgaclAclNew(void); - -/* #define GACLfreeAcl(x) GRSTgaclAclFree((x)) */ -int GRSTgaclAclFree(GRSTgaclAcl *); - -/* #define GACLprintAcl(x,y) GRSTgaclAclPrint((x),(y)) */ -int GRSTgaclAclPrint(GRSTgaclAcl *, FILE *); - -/* #define GACLsaveAcl(x,y) GRSTgaclAclSave((y),(x)) */ -int GRSTgaclAclSave(GRSTgaclAcl *, char *); - -/* #define GACLloadAcl(x) GRSTgaclFileLoadAcl((x)) */ -GRSTgaclAcl *GRSTgaclAclLoadFile(char *); - -/* #define GACLfindAclForFile(x) GRSTgaclFileFindAclname((x)) */ -char *GRSTgaclFileFindAclname(char *); - -/* #define GACLloadAclForFile(x) GRSTgaclFileLoadAcl((x)) */ -GRSTgaclAcl *GRSTgaclAclLoadforFile(char *); - -/* #define GACLisAclFile(x) GRSTgaclFileIsAcl((x)) */ -int GRSTgaclFileIsAcl(char *); - - -/* #define GACLnewUser(x) GRSTgaclUserNew((x)) */ -GRSTgaclUser *GRSTgaclUserNew(GRSTgaclCred *); - -/* #define GACLfreeUser(x) GRSTgaclUserFree((x)) */ -int GRSTgaclUserFree(GRSTgaclUser *); - -/* #define GACLuserAddCred(x,y) GRSTgaclUserAddCred((x),(y)) */ -int GRSTgaclUserAddCred(GRSTgaclUser *, GRSTgaclCred *); - -/* #define GACLuserHasCred(x,y) GRSTgaclUserHasCred((x),(y)) */ -int GRSTgaclUserHasCred(GRSTgaclUser *, GRSTgaclCred *); - -int GRSTgaclUserSetDNlists(GRSTgaclUser *, char *); - -/* #define GACLuserFindCredType(x,y) GRSTgaclUserFindCredtype((x),(y)) */ -GRSTgaclCred *GRSTgaclUserFindCredtype(GRSTgaclUser *, char *); - -/* #define GACLtestDnList(x,y) GRSTgaclDNlistHasUser((x),(y)) */ -int GRSTgaclDNlistHasUser(char *, GRSTgaclUser *); - -/* #define GACLtestUserAcl(x,y) GRSTgaclAclTestUser((x),(y)) */ -GRSTgaclPerm GRSTgaclAclTestUser(GRSTgaclAcl *, GRSTgaclUser *); - -/* #define GACLtestExclAcl(x,y) GRSTgaclAclTestexclUser((x),(y)) */ -GRSTgaclPerm GRSTgaclAclTestexclUser(GRSTgaclAcl *, GRSTgaclUser *); - - -char *GRSThttpUrlDecode(char *); - -/* #define GACLurlEncode(x) GRSThttpUrlEncode((x)) */ -char *GRSThttpUrlEncode(char *); - -/* #define GACLmildUrlEncode(x) GRSThttpMildUrlEncode((x)) */ -char *GRSThttpUrlMildencode(char *); - -int GRSTx509NameCmp(char *, char *); - -int GRSTx509KnownCriticalExts(X509 *); - -time_t GRSTasn1TimeToTimeT(char *); -int GRSTx509IsCA(X509 *); -int GRSTx509CheckChain(int *, X509_STORE_CTX *); -int GRSTx509VerifyCallback(int, X509_STORE_CTX *); - -int GRSTx509GetVomsCreds(int *, int, size_t, char *, X509 *, STACK_OF(X509) *, char *); -GRSTgaclCred *GRSTx509CompactToCred(char *); -int GRSTx509CompactCreds(int *, int, size_t, char *, STACK_OF(X509) *, char *); -char *GRSTx509CachedProxyFind(char *, char *, char *); -char *GRSTx509FindProxyFileName(void); -int GRSTx509MakeProxyCert(char **, FILE *, char *, char *, char *, int); -char *GRSTx509CachedProxyKeyFind(char *, char *, char *); -int GRSTx509MakeProxyRequest(char **, char *, char *, char *); -int GRSTx509CacheProxy(char *, char *, char *, char *); - -#define GRST_HEADFILE "gridsitehead.txt" -#define GRST_FOOTFILE "gridsitefoot.txt" -#define GRST_ADMIN_FILE "gridsite-admin.cgi" - -typedef struct { char *text; - void *next; } GRSThttpCharsList; - -typedef struct { size_t size; - GRSThttpCharsList *first; - GRSThttpCharsList *last; } GRSThttpBody; - -void GRSThttpBodyInit(GRSThttpBody *); -void GRSThttpPrintf(GRSThttpBody *, char *, ...); -int GRSThttpCopy(GRSThttpBody *, char *); -void GRSThttpWriteOut(GRSThttpBody *); -int GRSThttpPrintHeaderFooter(GRSThttpBody *, char *, char *); -char *GRSThttpGetCGI(char *); diff --git a/org.gridsite.core/project/build.properties b/org.gridsite.core/project/build.properties deleted file mode 100644 index e69de29..0000000 diff --git a/org.gridsite.core/project/configure.properties.xml b/org.gridsite.core/project/configure.properties.xml deleted file mode 100644 index 6ee8706..0000000 --- a/org.gridsite.core/project/configure.properties.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - diff --git a/org.gridsite.core/project/dependencies.properties b/org.gridsite.core/project/dependencies.properties deleted file mode 100644 index 2a7383b..0000000 --- a/org.gridsite.core/project/dependencies.properties +++ /dev/null @@ -1,9 +0,0 @@ -################################################################### -# System dependencies -################################################################### - -org.glite.version = HEAD -org.glite.core.version = HEAD - -# Component dependencies tag = do not remove this line = - diff --git a/org.gridsite.core/project/gridsite.core.csf.xml b/org.gridsite.core/project/gridsite.core.csf.xml deleted file mode 100644 index 7ca38dc..0000000 --- a/org.gridsite.core/project/gridsite.core.csf.xml +++ /dev/null @@ -1,221 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The org.glite and org.gridsite.core modules have been updated, please rerun the configuration file - - - - The org.glite and org.gridsite.core modules have been updated, please rerun the configuration file - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.gridsite.core/project/properties.xml b/org.gridsite.core/project/properties.xml deleted file mode 100644 index 74f88dc..0000000 --- a/org.gridsite.core/project/properties.xml +++ /dev/null @@ -1,53 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/org.gridsite.core/project/taskdefs.xml b/org.gridsite.core/project/taskdefs.xml deleted file mode 100644 index 9c35cef..0000000 --- a/org.gridsite.core/project/taskdefs.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/org.gridsite.core/project/version.properties b/org.gridsite.core/project/version.properties deleted file mode 100644 index 271daff..0000000 --- a/org.gridsite.core/project/version.properties +++ /dev/null @@ -1,4 +0,0 @@ -#Fri Dec 10 12:31:28 CET 2004 -module.version=1.1.3 -module.build=71 -module.age=2 diff --git a/org.gridsite.core/src/Doxyfile b/org.gridsite.core/src/Doxyfile deleted file mode 100644 index e47d005..0000000 --- a/org.gridsite.core/src/Doxyfile +++ /dev/null @@ -1,993 +0,0 @@ -# Doxyfile 1.2.18 - -# This file describes the settings to be used by the documentation system -# doxygen (www.doxygen.org) for a project -# -# All text after a hash (#) is considered a comment and will be ignored -# The format is: -# TAG = value [value, ...] -# For lists items can also be appended using: -# TAG += value [value, ...] -# Values that contain spaces should be placed between quotes (" ") - -#--------------------------------------------------------------------------- -# General configuration options -#--------------------------------------------------------------------------- - -# The PROJECT_NAME tag is a single word (or a sequence of words surrounded -# by quotes) that should identify the project. - -PROJECT_NAME = - -# The PROJECT_NUMBER tag can be used to enter a project or revision number. -# This could be handy for archiving the generated documentation or -# if some version control system is used. - -PROJECT_NUMBER = - -# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) -# base path where the generated documentation will be put. -# If a relative path is entered, it will be relative to the location -# where doxygen was started. If left blank the current directory will be used. - -OUTPUT_DIRECTORY = - -# The OUTPUT_LANGUAGE tag is used to specify the language in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all constant output in the proper language. -# The default language is English, other supported languages are: -# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, -# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en -# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese, -# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian. - -OUTPUT_LANGUAGE = English - -# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in -# documentation are documented, even if no documentation was available. -# Private class members and static file members will be hidden unless -# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES - -EXTRACT_ALL = YES - -# If the EXTRACT_PRIVATE tag is set to YES all private members of a class -# will be included in the documentation. - -EXTRACT_PRIVATE = NO - -# If the EXTRACT_STATIC tag is set to YES all static members of a file -# will be included in the documentation. - -EXTRACT_STATIC = NO - -# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) -# defined locally in source files will be included in the documentation. -# If set to NO only classes defined in header files are included. - -EXTRACT_LOCAL_CLASSES = NO - -# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all -# undocumented members of documented classes, files or namespaces. -# If set to NO (the default) these members will be included in the -# various overviews, but no documentation section is generated. -# This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_MEMBERS = NO - -# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all -# undocumented classes that are normally visible in the class hierarchy. -# If set to NO (the default) these class will be included in the various -# overviews. This option has no effect if EXTRACT_ALL is enabled. - -HIDE_UNDOC_CLASSES = NO - -# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all -# friend (class|struct|union) declarations. -# If set to NO (the default) these declarations will be included in the -# documentation. - -HIDE_FRIEND_COMPOUNDS = NO - -# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will -# include brief member descriptions after the members that are listed in -# the file and class documentation (similar to JavaDoc). -# Set to NO to disable this. - -BRIEF_MEMBER_DESC = YES - -# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend -# the brief description of a member or function before the detailed description. -# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the -# brief descriptions will be completely suppressed. - -REPEAT_BRIEF = YES - -# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then -# Doxygen will generate a detailed section even if there is only a brief -# description. - -ALWAYS_DETAILED_SEC = NO - -# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited -# members of a class in the documentation of that class as if those members were -# ordinary class members. Constructors, destructors and assignment operators of -# the base classes will not be shown. - -INLINE_INHERITED_MEMB = NO - -# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full -# path before files name in the file list and in the header files. If set -# to NO the shortest path that makes the file name unique will be used. - -FULL_PATH_NAMES = NO - -# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag -# can be used to strip a user defined part of the path. Stripping is -# only done if one of the specified strings matches the left-hand part of -# the path. It is allowed to use relative paths in the argument list. - -STRIP_FROM_PATH = - -# The INTERNAL_DOCS tag determines if documentation -# that is typed after a \internal command is included. If the tag is set -# to NO (the default) then the documentation will be excluded. -# Set it to YES to include the internal documentation. - -INTERNAL_DOCS = NO - -# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct -# doxygen to hide any special comment blocks from generated source code -# fragments. Normal C and C++ comments will always remain visible. - -STRIP_CODE_COMMENTS = YES - -# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate -# file names in lower case letters. If set to YES upper case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# users are adviced to set this option to NO. - -CASE_SENSE_NAMES = YES - -# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter -# (but less readable) file names. This can be useful is your file systems -# doesn't support long names like on DOS, Mac, or CD-ROM. - -SHORT_NAMES = NO - -# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen -# will show members with their full class and namespace scopes in the -# documentation. If set to YES the scope will be hidden. - -HIDE_SCOPE_NAMES = NO - -# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen -# will generate a verbatim copy of the header file for each class for -# which an include is specified. Set to NO to disable this. - -VERBATIM_HEADERS = YES - -# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen -# will put list of the files that are included by a file in the documentation -# of that file. - -SHOW_INCLUDE_FILES = NO - -# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen -# will interpret the first line (until the first dot) of a JavaDoc-style -# comment as the brief description. If set to NO, the JavaDoc -# comments will behave just like the Qt-style comments (thus requiring an -# explict @brief command for a brief description. - -JAVADOC_AUTOBRIEF = NO - -# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen -# treat a multi-line C++ special comment block (i.e. a block of //! or /// -# comments) as a brief description. This used to be the default behaviour. -# The new default is to treat a multi-line C++ comment block as a detailed -# description. Set this tag to YES if you prefer the old behaviour instead. - -MULTILINE_CPP_IS_BRIEF = NO - -# If the DETAILS_AT_TOP tag is set to YES then Doxygen -# will output the detailed description near the top, like JavaDoc. -# If set to NO, the detailed description appears after the member -# documentation. - -DETAILS_AT_TOP = NO - -# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented -# member inherits the documentation from any documented member that it -# reimplements. - -INHERIT_DOCS = YES - -# If the INLINE_INFO tag is set to YES (the default) then a tag [inline] -# is inserted in the documentation for inline members. - -INLINE_INFO = YES - -# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen -# will sort the (detailed) documentation of file and class members -# alphabetically by member name. If set to NO the members will appear in -# declaration order. - -SORT_MEMBER_DOCS = YES - -# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC -# tag is set to YES, then doxygen will reuse the documentation of the first -# member in the group (if any) for the other members of the group. By default -# all members of a group must be documented explicitly. - -DISTRIBUTE_GROUP_DOC = NO - -# The TAB_SIZE tag can be used to set the number of spaces in a tab. -# Doxygen uses this value to replace tabs by spaces in code fragments. - -TAB_SIZE = 8 - -# The GENERATE_TODOLIST tag can be used to enable (YES) or -# disable (NO) the todo list. This list is created by putting \todo -# commands in the documentation. - -GENERATE_TODOLIST = YES - -# The GENERATE_TESTLIST tag can be used to enable (YES) or -# disable (NO) the test list. This list is created by putting \test -# commands in the documentation. - -GENERATE_TESTLIST = YES - -# The GENERATE_BUGLIST tag can be used to enable (YES) or -# disable (NO) the bug list. This list is created by putting \bug -# commands in the documentation. - -GENERATE_BUGLIST = YES - -# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or -# disable (NO) the deprecated list. This list is created by putting \deprecated commands in the documentation. - -GENERATE_DEPRECATEDLIST= YES - -# This tag can be used to specify a number of aliases that acts -# as commands in the documentation. An alias has the form "name=value". -# For example adding "sideeffect=\par Side Effects:\n" will allow you to -# put the command \sideeffect (or @sideeffect) in the documentation, which -# will result in a user defined paragraph with heading "Side Effects:". -# You can put \n's in the value part of an alias to insert newlines. - -ALIASES = - -# The ENABLED_SECTIONS tag can be used to enable conditional -# documentation sections, marked by \if sectionname ... \endif. - -ENABLED_SECTIONS = - -# The MAX_INITIALIZER_LINES tag determines the maximum number of lines -# the initial value of a variable or define consist of for it to appear in -# the documentation. If the initializer consists of more lines than specified -# here it will be hidden. Use a value of 0 to hide initializers completely. -# The appearance of the initializer of individual variables and defines in the -# documentation can be controlled using \showinitializer or \hideinitializer -# command in the documentation regardless of this setting. - -MAX_INITIALIZER_LINES = 30 - -# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources -# only. Doxygen will then generate output that is more tailored for C. -# For instance some of the names that are used will be different. The list -# of all members will be omitted, etc. - -OPTIMIZE_OUTPUT_FOR_C = YES - -# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources -# only. Doxygen will then generate output that is more tailored for Java. -# For instance namespaces will be presented as packages, qualified scopes -# will look different, etc. - -OPTIMIZE_OUTPUT_JAVA = NO - -# Set the SHOW_USED_FILES tag to NO to disable the list of files generated -# at the bottom of the documentation of classes and structs. If set to YES the -# list will mention the files that were used to generate the documentation. - -SHOW_USED_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to warning and progress messages -#--------------------------------------------------------------------------- - -# The QUIET tag can be used to turn on/off the messages that are generated -# by doxygen. Possible values are YES and NO. If left blank NO is used. - -QUIET = NO - -# The WARNINGS tag can be used to turn on/off the warning messages that are -# generated by doxygen. Possible values are YES and NO. If left blank -# NO is used. - -WARNINGS = YES - -# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings -# for undocumented members. If EXTRACT_ALL is set to YES then this flag will -# automatically be disabled. - -WARN_IF_UNDOCUMENTED = YES - -# The WARN_FORMAT tag determines the format of the warning messages that -# doxygen can produce. The string should contain the $file, $line, and $text -# tags, which will be replaced by the file and line number from which the -# warning originated and the warning text. - -WARN_FORMAT = "$file:$line: $text" - -# The WARN_LOGFILE tag can be used to specify a file to which warning -# and error messages should be written. If left blank the output is written -# to stderr. - -WARN_LOGFILE = - -#--------------------------------------------------------------------------- -# configuration options related to the input files -#--------------------------------------------------------------------------- - -# The INPUT tag can be used to specify the files and/or directories that contain -# documented source files. You may enter file names like "myfile.cpp" or -# directories like "/usr/src/myproject". Separate the files or directories -# with spaces. - -INPUT = - -# If the value of the INPUT tag contains directories, you can use the -# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank the following patterns are tested: -# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp -# *.h++ *.idl *.odl - -FILE_PATTERNS = - -# The RECURSIVE tag can be used to turn specify whether or not subdirectories -# should be searched for input files as well. Possible values are YES and NO. -# If left blank NO is used. - -RECURSIVE = NO - -# The EXCLUDE tag can be used to specify files and/or directories that should -# excluded from the INPUT source files. This way you can easily exclude a -# subdirectory from a directory tree whose root is specified with the INPUT tag. - -EXCLUDE = - -# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories -# that are symbolic links (a Unix filesystem feature) are excluded from the input. - -EXCLUDE_SYMLINKS = NO - -# If the value of the INPUT tag contains directories, you can use the -# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude -# certain files from those directories. - -EXCLUDE_PATTERNS = - -# The EXAMPLE_PATH tag can be used to specify one or more files or -# directories that contain example code fragments that are included (see -# the \include command). - -EXAMPLE_PATH = - -# If the value of the EXAMPLE_PATH tag contains directories, you can use the -# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp -# and *.h) to filter out the source-files in the directories. If left -# blank all files are included. - -EXAMPLE_PATTERNS = - -# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be -# searched for input files to be used with the \include or \dontinclude -# commands irrespective of the value of the RECURSIVE tag. -# Possible values are YES and NO. If left blank NO is used. - -EXAMPLE_RECURSIVE = NO - -# The IMAGE_PATH tag can be used to specify one or more files or -# directories that contain image that are included in the documentation (see -# the \image command). - -IMAGE_PATH = - -# The INPUT_FILTER tag can be used to specify a program that doxygen should -# invoke to filter for each input file. Doxygen will invoke the filter program -# by executing (via popen()) the command , where -# is the value of the INPUT_FILTER tag, and is the name of an -# input file. Doxygen will then use the output that the filter program writes -# to standard output. - -INPUT_FILTER = - -# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using -# INPUT_FILTER) will be used to filter the input files when producing source -# files to browse (i.e. when SOURCE_BROWSER is set to YES). - -FILTER_SOURCE_FILES = NO - -#--------------------------------------------------------------------------- -# configuration options related to source browsing -#--------------------------------------------------------------------------- - -# If the SOURCE_BROWSER tag is set to YES then a list of source files will -# be generated. Documented entities will be cross-referenced with these sources. - -SOURCE_BROWSER = NO - -# Setting the INLINE_SOURCES tag to YES will include the body -# of functions and classes directly in the documentation. - -INLINE_SOURCES = NO - -# If the REFERENCED_BY_RELATION tag is set to YES (the default) -# then for each documented function all documented -# functions referencing it will be listed. - -REFERENCED_BY_RELATION = NO - -# If the REFERENCES_RELATION tag is set to YES (the default) -# then for each documented function all documented entities -# called/used by that function will be listed. - -REFERENCES_RELATION = NO - -#--------------------------------------------------------------------------- -# configuration options related to the alphabetical class index -#--------------------------------------------------------------------------- - -# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index -# of all compounds will be generated. Enable this if the project -# contains a lot of classes, structs, unions or interfaces. - -ALPHABETICAL_INDEX = YES - -# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then -# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns -# in which this list will be split (can be a number in the range [1..20]) - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all -# classes will be put under the same header in the alphabetical index. -# The IGNORE_PREFIX tag can be used to specify one or more prefixes that -# should be ignored while generating the index headers. - -IGNORE_PREFIX = - -#--------------------------------------------------------------------------- -# configuration options related to the HTML output -#--------------------------------------------------------------------------- - -# If the GENERATE_HTML tag is set to YES (the default) Doxygen will -# generate HTML output. - -GENERATE_HTML = YES - -# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `html' will be used as the default path. - -HTML_OUTPUT = doxygen - -# The HTML_FILE_EXTENSION tag can be used to specify the file extension for -# each generated HTML page (for example: .htm,.php,.asp). If it is left blank -# doxygen will generate files with .html extension. - -HTML_FILE_EXTENSION = .html - -# The HTML_HEADER tag can be used to specify a personal HTML header for -# each generated HTML page. If it is left blank doxygen will generate a -# standard header. - -HTML_HEADER = - -# The HTML_FOOTER tag can be used to specify a personal HTML footer for -# each generated HTML page. If it is left blank doxygen will generate a -# standard footer. - -HTML_FOOTER = - -# The HTML_STYLESHEET tag can be used to specify a user defined cascading -# style sheet that is used by each HTML page. It can be used to -# fine-tune the look of the HTML output. If the tag is left blank doxygen -# will generate a default style sheet - -HTML_STYLESHEET = doxygen.css - -# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, -# files or namespaces will be aligned in HTML using tables. If set to -# NO a bullet list will be used. - -HTML_ALIGN_MEMBERS = YES - -# If the GENERATE_HTMLHELP tag is set to YES, additional index files -# will be generated that can be used as input for tools like the -# Microsoft HTML help workshop to generate a compressed HTML help file (.chm) -# of the generated HTML documentation. - -GENERATE_HTMLHELP = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can -# be used to specify the file name of the resulting .chm file. You -# can add a path in front of the file if the result should not be -# written to the html output dir. - -CHM_FILE = - -# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can -# be used to specify the location (absolute path including file name) of -# the HTML help compiler (hhc.exe). If non empty doxygen will try to run -# the html help compiler on the generated index.hhp. - -HHC_LOCATION = - -# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag -# controls if a separate .chi index file is generated (YES) or that -# it should be included in the master .chm file (NO). - -GENERATE_CHI = NO - -# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag -# controls whether a binary table of contents is generated (YES) or a -# normal table of contents (NO) in the .chm file. - -BINARY_TOC = NO - -# The TOC_EXPAND flag can be set to YES to add extra items for group members -# to the contents of the Html help documentation and to the tree view. - -TOC_EXPAND = NO - -# The DISABLE_INDEX tag can be used to turn on/off the condensed index at -# top of each HTML page. The value NO (the default) enables the index and -# the value YES disables it. - -DISABLE_INDEX = YES - -# This tag can be used to set the number of enum values (range [1..20]) -# that doxygen will group on one line in the generated HTML documentation. - -ENUM_VALUES_PER_LINE = 4 - -# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be -# generated containing a tree-like index structure (just like the one that -# is generated for HTML Help). For this to work a browser that supports -# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+, -# or Internet explorer 4.0+). Note that for large projects the tree generation -# can take a very long time. In such cases it is better to disable this feature. -# Windows users are probably better off using the HTML help feature. - -GENERATE_TREEVIEW = NO - -# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be -# used to set the initial width (in pixels) of the frame in which the tree -# is shown. - -TREEVIEW_WIDTH = 250 - -#--------------------------------------------------------------------------- -# configuration options related to the LaTeX output -#--------------------------------------------------------------------------- - -# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will -# generate Latex output. - -GENERATE_LATEX = NO - -# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `latex' will be used as the default path. - -LATEX_OUTPUT = latex - -# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be invoked. If left blank `latex' will be used as the default command name. - -LATEX_CMD_NAME = latex - -# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to -# generate index for LaTeX. If left blank `makeindex' will be used as the -# default command name. - -MAKEINDEX_CMD_NAME = makeindex - -# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact -# LaTeX documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_LATEX = NO - -# The PAPER_TYPE tag can be used to set the paper type that is used -# by the printer. Possible values are: a4, a4wide, letter, legal and -# executive. If left blank a4wide will be used. - -PAPER_TYPE = a4wide - -# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX -# packages that should be included in the LaTeX output. - -EXTRA_PACKAGES = - -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for -# the generated latex document. The header should contain everything until -# the first chapter. If it is left blank doxygen will generate a -# standard header. Notice: only use this tag if you know what you are doing! - -LATEX_HEADER = - -# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated -# is prepared for conversion to pdf (using ps2pdf). The pdf file will -# contain links (just like the HTML output) instead of page references -# This makes the output suitable for online browsing using a pdf viewer. - -PDF_HYPERLINKS = NO - -# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of -# plain latex in the generated Makefile. Set this option to YES to get a -# higher quality PDF documentation. - -USE_PDFLATEX = NO - -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. -# command to the generated LaTeX files. This will instruct LaTeX to keep -# running if errors occur, instead of asking the user for help. -# This option is also used when generating formulas in HTML. - -LATEX_BATCHMODE = NO - -#--------------------------------------------------------------------------- -# configuration options related to the RTF output -#--------------------------------------------------------------------------- - -# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output -# The RTF output is optimised for Word 97 and may not look very pretty with -# other RTF readers or editors. - -GENERATE_RTF = NO - -# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `rtf' will be used as the default path. - -RTF_OUTPUT = rtf - -# If the COMPACT_RTF tag is set to YES Doxygen generates more compact -# RTF documents. This may be useful for small projects and may help to -# save some trees in general. - -COMPACT_RTF = NO - -# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated -# will contain hyperlink fields. The RTF file will -# contain links (just like the HTML output) instead of page references. -# This makes the output suitable for online browsing using WORD or other -# programs which support those fields. -# Note: wordpad (write) and others do not support links. - -RTF_HYPERLINKS = NO - -# Load stylesheet definitions from file. Syntax is similar to doxygen's -# config file, i.e. a series of assigments. You only have to provide -# replacements, missing definitions are set to their default value. - -RTF_STYLESHEET_FILE = - -# Set optional variables used in the generation of an rtf document. -# Syntax is similar to doxygen's config file. - -RTF_EXTENSIONS_FILE = - -#--------------------------------------------------------------------------- -# configuration options related to the man page output -#--------------------------------------------------------------------------- - -# If the GENERATE_MAN tag is set to YES (the default) Doxygen will -# generate man pages - -GENERATE_MAN = NO - -# The MAN_OUTPUT tag is used to specify where the man pages will be put. -# If a relative path is entered the value of OUTPUT_DIRECTORY will be -# put in front of it. If left blank `man' will be used as the default path. - -MAN_OUTPUT = man - -# The MAN_EXTENSION tag determines the extension that is added to -# the generated man pages (default is the subroutine's section .3) - -MAN_EXTENSION = .3 - -# If the MAN_LINKS tag is set to YES and Doxygen generates man output, -# then it will generate one additional man file for each entity -# documented in the real man page(s). These additional files -# only source the real man page, but without them the man command -# would be unable to find the correct page. The default is NO. - -MAN_LINKS = NO - -#--------------------------------------------------------------------------- -# configuration options related to the XML output -#--------------------------------------------------------------------------- - -# If the GENERATE_XML tag is set to YES Doxygen will -# generate an XML file that captures the structure of -# the code including all documentation. Note that this -# feature is still experimental and incomplete at the -# moment. - -GENERATE_XML = NO - -# The XML_SCHEMA tag can be used to specify an XML schema, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_SCHEMA = - -# The XML_DTD tag can be used to specify an XML DTD, -# which can be used by a validating XML parser to check the -# syntax of the XML files. - -XML_DTD = - -#--------------------------------------------------------------------------- -# configuration options for the AutoGen Definitions output -#--------------------------------------------------------------------------- - -# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will -# generate an AutoGen Definitions (see autogen.sf.net) file -# that captures the structure of the code including all -# documentation. Note that this feature is still experimental -# and incomplete at the moment. - -GENERATE_AUTOGEN_DEF = NO - -#--------------------------------------------------------------------------- -# Configuration options related to the preprocessor -#--------------------------------------------------------------------------- - -# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will -# evaluate all C-preprocessor directives found in the sources and include -# files. - -ENABLE_PREPROCESSING = NO - -# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro -# names in the source code. If set to NO (the default) only conditional -# compilation will be performed. Macro expansion can be done in a controlled -# way by setting EXPAND_ONLY_PREDEF to YES. - -MACRO_EXPANSION = NO - -# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES -# then the macro expansion is limited to the macros specified with the -# PREDEFINED and EXPAND_AS_PREDEFINED tags. - -EXPAND_ONLY_PREDEF = NO - -# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files -# in the INCLUDE_PATH (see below) will be search if a #include is found. - -SEARCH_INCLUDES = YES - -# The INCLUDE_PATH tag can be used to specify one or more directories that -# contain include files that are not input files but should be processed by -# the preprocessor. - -INCLUDE_PATH = - -# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard -# patterns (like *.h and *.hpp) to filter out the header-files in the -# directories. If left blank, the patterns specified with FILE_PATTERNS will -# be used. - -INCLUDE_FILE_PATTERNS = - -# The PREDEFINED tag can be used to specify one or more macro names that -# are defined before the preprocessor is started (similar to the -D option of -# gcc). The argument of the tag is a list of macros of the form: name -# or name=definition (no spaces). If the definition and the = are -# omitted =1 is assumed. - -PREDEFINED = - -# If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then -# this tag can be used to specify a list of macro names that should be expanded. -# The macro definition that is found in the sources will be used. -# Use the PREDEFINED tag if you want to use a different macro definition. - -EXPAND_AS_DEFINED = - -# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then -# doxygen's preprocessor will remove all function-like macros that are alone -# on a line, have an all uppercase name, and do not end with a semicolon. Such -# function macros are typically used for boiler-plate code, and will confuse the -# parser if not removed. - -SKIP_FUNCTION_MACROS = YES - -#--------------------------------------------------------------------------- -# Configuration::addtions related to external references -#--------------------------------------------------------------------------- - -# The TAGFILES tag can be used to specify one or more tagfiles. - -TAGFILES = - -# When a file name is specified after GENERATE_TAGFILE, doxygen will create -# a tag file that is based on the input files it reads. - -GENERATE_TAGFILE = - -# If the ALLEXTERNALS tag is set to YES all external classes will be listed -# in the class index. If set to NO only the inherited external classes -# will be listed. - -ALLEXTERNALS = NO - -# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will -# be listed. - -EXTERNAL_GROUPS = YES - -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of `which perl'). - -PERL_PATH = /usr/bin/perl - -#--------------------------------------------------------------------------- -# Configuration options related to the dot tool -#--------------------------------------------------------------------------- - -# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will -# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or -# super classes. Setting the tag to NO turns the diagrams off. Note that this -# option is superceded by the HAVE_DOT option below. This is only a fallback. It is -# recommended to install and use dot, since it yield more powerful graphs. - -CLASS_DIAGRAMS = YES - -# If set to YES, the inheritance and collaboration graphs will hide -# inheritance and usage relations if the target is undocumented -# or is not a class. - -HIDE_UNDOC_RELATIONS = YES - -# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is -# available from the path. This tool is part of Graphviz, a graph visualization -# toolkit from AT&T and Lucent Bell Labs. The other options in this section -# have no effect if this option is set to NO (the default) - -HAVE_DOT = NO - -# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect inheritance relations. Setting this tag to YES will force the -# the CLASS_DIAGRAMS tag to NO. - -CLASS_GRAPH = YES - -# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen -# will generate a graph for each documented class showing the direct and -# indirect implementation dependencies (inheritance, containment, and -# class references variables) of the class with other documented classes. - -COLLABORATION_GRAPH = YES - -# If set to YES, the inheritance and collaboration graphs will show the -# relations between templates and their instances. - -TEMPLATE_RELATIONS = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT -# tags are set to YES then doxygen will generate a graph for each documented -# file showing the direct and indirect include dependencies of the file with -# other documented files. - -INCLUDE_GRAPH = YES - -# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and -# HAVE_DOT tags are set to YES then doxygen will generate a graph for each -# documented header file showing the documented files that directly or -# indirectly include this file. - -INCLUDED_BY_GRAPH = YES - -# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen -# will graphical hierarchy of all classes instead of a textual one. - -GRAPHICAL_HIERARCHY = YES - -# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. Possible values are png, jpg, or gif -# If left blank png will be used. - -DOT_IMAGE_FORMAT = png - -# The tag DOT_PATH can be used to specify the path where the dot tool can be -# found. If left blank, it is assumed the dot tool can be found on the path. - -DOT_PATH = - -# The DOTFILE_DIRS tag can be used to specify one or more directories that -# contain dot files that are included in the documentation (see the -# \dotfile command). - -DOTFILE_DIRS = - -# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - -MAX_DOT_GRAPH_WIDTH = 1024 - -# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height -# (in pixels) of the graphs generated by dot. If a graph becomes larger than -# this value, doxygen will try to truncate the graph, so that it fits within -# the specified constraint. Beware that most browsers cannot cope with very -# large images. - -MAX_DOT_GRAPH_HEIGHT = 1024 - -# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will -# generate a legend page explaining the meaning of the various boxes and -# arrows in the dot generated graphs. - -GENERATE_LEGEND = YES - -# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will -# remove the intermedate dot files that are used to generate -# the various graphs. - -DOT_CLEANUP = YES - -#--------------------------------------------------------------------------- -# Configuration::addtions related to the search engine -#--------------------------------------------------------------------------- - -# The SEARCHENGINE tag specifies whether or not a search engine should be -# used. If set to NO the values of all tags below this one will be ignored. - -SEARCHENGINE = NO - -# The CGI_NAME tag should be the name of the CGI script that -# starts the search engine (doxysearch) with the correct parameters. -# A script with this name will be generated by doxygen. - -CGI_NAME = search.cgi - -# The CGI_URL tag should be the absolute URL to the directory where the -# cgi binaries are located. See the documentation of your http daemon for -# details. - -CGI_URL = - -# The DOC_URL tag should be the absolute URL to the directory where the -# documentation is located. If left blank the absolute path to the -# documentation, with file:// prepended to it, will be used. - -DOC_URL = - -# The DOC_ABSPATH tag should be the absolute path to the directory where the -# documentation is located. If left blank the directory on the local machine -# will be used. - -DOC_ABSPATH = - -# The BIN_ABSPATH tag must point to the directory where the doxysearch binary -# is installed. - -BIN_ABSPATH = /usr/local/bin/ - -# The EXT_DOC_PATHS tag can be used to specify one or more paths to -# documentation generated for other projects. This allows doxysearch to search -# the documentation for these projects as well. - -EXT_DOC_PATHS = diff --git a/org.gridsite.core/src/Makefile b/org.gridsite.core/src/Makefile deleted file mode 100644 index bd66586..0000000 --- a/org.gridsite.core/src/Makefile +++ /dev/null @@ -1,280 +0,0 @@ -# -# Andrew McNab and Shiv Kaushal, University of Manchester. -# Copyright (c) 2002-4. All rights reserved. -# -# Redistribution and use in source and binary forms, with or -# without modification, are permitted provided that the following -# conditions are met: -# -# o Redistributions of source code must retain the above -# copyright notice, this list of conditions and the following -# disclaimer. -# o Redistributions in binary form must reproduce the above -# copyright notice, this list of conditions and the following -# disclaimer in the documentation and/or other materials -# provided with the distribution. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND -# CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, -# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS -# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -# TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -# ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY -# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -# POSSIBILITY OF SUCH DAMAGE. -# -#--------------------------------------------------------------- -# For more information about GridSite: http://www.gridsite.org/ -#--------------------------------------------------------------- - -include ../VERSION - -RPMCMD=$(shell if [ -x /usr/bin/rpmbuild ] ; then echo /usr/bin/rpmbuild; else echo rpm; fi) - -ifndef MYRPMDIR -export MYRPMDIR=$(shell pwd)/../RPMTMP -endif - -ifndef prefix -export prefix=/usr/local -endif - -ifndef MYCFLAGS -export MYCFLAGS=-I. -I../interface -I/usr/include/httpd -I/usr/include/apr-0 -I/opt/glite/include -endif - -ifndef OPENSSL_FLAGS -export OPENSSL_FLAGS=-I/usr/include/openssl -endif - -ifndef MYLDFLAGS -export MYLDFLAGS=-L. -# export MYLDFLAGS=-L. -L/opt/glite/lib -lvomsc -endif - -ifndef OPENSSL_LIBS -export OPENSSL_LIBS=-L/usr/lib/openssl -endif - -# -# Build -# - -build: libgridsite.so.$(VERSION) libgridsite.a htcp mod_gridsite.so \ - urlencode findproxyfile real-gridsite-admin.cgi \ - # gridsite-delegation.cgi # htproxyput - -libgridsite.so.$(VERSION): grst_x509.o grst_gacl.o grst_http.o - gcc -shared -Wl,-soname,libgridsite.so.$(MINOR_VERSION) \ - -o libgridsite.so.$(PATCH_VERSION) grst_x509.o grst_gacl.o grst_http.o - -libgridsite.a: grst_x509.o grst_gacl.o grst_http.o - ar src libgridsite.a grst_x509.o grst_gacl.o grst_http.o - -grst_x509.o: grst_x509.c ../interface/gridsite.h - gcc $(MYCFLAGS) $(OPENSSL_FLAGS) \ - -I/usr/kerberos/include -c grst_x509.c - -grst_gacl.o: grst_gacl.c ../interface/gridsite.h - gcc $(MYCFLAGS) $(OPENSSL_FLAGS) \ - -I/usr/kerberos/include `xml2-config --cflags` -c grst_gacl.c - -grst_http.o: grst_http.c ../interface/gridsite.h - gcc $(MYCFLAGS) $(OPENSSL_FLAGS) \ - -I/usr/kerberos/include -c grst_http.c - -urlencode: urlencode.c libgridsite.a - gcc -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) \ - -o urlencode urlencode.c -L. \ - $(OPENSSL_FLAGS) -I/usr/kerberos/include -lgridsite - -htcp: htcp.c - gcc -DVERSION=\"$(PATCH_VERSION)\" -I. -o htcp htcp.c \ - `curl-config --cflags` `curl-config --libs` - -mod_gridsite.so: mod_gridsite.c mod_ssl-private.h libgridsite.a - gcc $(MYCFLAGS) -shared -Wl,-soname=gridsite_module \ - $(OPENSSL_FLAGS) -I/usr/kerberos/include \ - -I/usr/include/libxml2 \ - -DVERSION=\"$(VERSION)\" -o mod_gridsite.so \ - mod_gridsite.c $(MYLDFLAGS) -lxml2 -lm -lz -lgridsite - -real-gridsite-admin.cgi: grst_admin_main.c grst_admin_gacl.c \ - grst_admin_file.c grst_admin.h - gcc $(MYCFLAGS) $(MYLDFLAGS) -o real-gridsite-admin.cgi \ - grst_admin_main.c \ - grst_admin_gacl.c \ - grst_admin_file.c \ - $(OPENSSL_FLAGS) -I/usr/kerberos/include \ - -DVERSION=\"$(VERSION)\" $(OPENSSL_LIBS) -lgridsite -lssl -lcrypto -lxml2 -lz -lm - -findproxyfile: findproxyfile.c libgridsite.a - gcc -DVERSION=\"$(PATCH_VERSION)\" $(MYCFLAGS) $(MYLDFLAGS) \ - -o findproxyfile findproxyfile.c -L. \ - $(OPENSSL_FLAGS) -I/usr/kerberos/include -lgridsite \ - $(OPENSSL_LIBS) -lssl -lcrypto -lxml2 -lz -lm - -apidoc: - doxygen Doxyfile - -gaclexample: gaclexample.c libgridsite.a - gcc -o gaclexample gaclexample.c -I. -L. \ - $(OPENSSL_FLAGS) -I/usr/kerberos/include -lgridsite \ - -lssl -lcrypto -lxml2 -lz -lm - -# -# Delegation machinery, including SOAP delegation portType. To build this -# you need to install gSOAP and set GSOAPDIR to the directory containing -# soapcpp2 and stdsoap2.h (unless GSOAPDIR is set already) -# - -ifndef GSOAPDIR -export GSOAPDIR=/usr/local/lib/gsoap -endif - -delegation.wsdl: delegation.h - ls -lR $(GSOAPDIR) - $(GSOAPDIR)/bin/soapcpp2 -c delegation.h - -libstdsoap2.a: $(GSOAPDIR)/stdsoap2.c - gcc -c -DWITH_OPENSSL $(GSOAPDIR)/stdsoap2.c - ar src libstdsoap2.a stdsoap2.o - -gridsite-delegation.cgi: grst-delegation.c delegation.h delegation.wsdl \ - soapC.c soapServer.c - gcc $(MYCFLAGS) $(MYLDFLAGS) -o gridsite-delegation.cgi \ - grst-delegation.c \ - $(OPENSSL_FLAGS) -I/usr/kerberos/include -I$(GSOAPDIR)/include \ - -DVERSION=\"$(VERSION)\" -L$(GSOAPDIR)/lib \ - soapC.c soapServer.c -lgsoap \ - -lgridsite -lcurl -lz -lssl -lcrypto -lxml2 -lm - -htproxyput: htproxyput.c delegation.h delegation.wsdl \ - soapC.c soapServer.c - gcc $(MYCFLAGS) $(MYLDFLAGS) -o htproxyput \ - htproxyput.c \ - $(OPENSSL_FLAGS) -I/usr/kerberos/include \ - -g -DVERSION=\"$(VERSION)\" \ - -I$(GSOAPDIR)/include -DWITH_OPENSSL -L$(GSOAPDIR)/lib \ - soapC.c soapClient.c -lgsoap \ - -lgridsite -lcurl -lz -lssl -lcrypto -lxml2 -lm - -proxyput-example: proxyput-example.c delegation.h delegation.wsdl \ - soapC.c soapServer.c libstdsoap2.a - gcc $(MYCFLAGS) $(MYLDFLAGS) -o proxyput-example \ - proxyput-example.c \ - $(OPENSSL_FLAGS) -I/usr/kerberos/include \ - -g -DVERSION=\"$(VERSION)\" \ - -I$(GSOAPDIR) -DWITH_OPENSSL \ - soapC.c soapClient.c libstdsoap2.a \ - -lgridsite -lcurl -lz -lssl -lcrypto -lxml2 -lm - -clean: - -# -# Install -# - -install: apidoc - mkdir -p $(prefix)/include \ - $(prefix)/lib \ - $(prefix)/bin \ - $(prefix)/sbin \ - $(prefix)/share/man/man1 \ - $(prefix)/lib/httpd/modules \ - $(prefix)/share/doc/gridsite-$(PATCH_VERSION) - cp -f ../interface/gridsite.h $(prefix)/include - cp -f ../interface/gridsite-gacl.h $(prefix)/include - cp -f urlencode $(prefix)/bin - cp -f findproxyfile $(prefix)/bin - cp -f libgridsite.a $(prefix)/lib - cp -f real-gridsite-admin.cgi $(prefix)/sbin - cp -f libgridsite.so.$(PATCH_VERSION) $(prefix)/lib - ln -sf libgridsite.so.$(PATCH_VERSION) \ - $(prefix)/lib/libgridsite.so - ln -sf libgridsite.so.$(PATCH_VERSION) \ - $(prefix)/lib/libgridsite.so.$(MAJOR_VERSION) - ln -sf libgridsite.so.$(PATCH_VERSION) \ - $(prefix)/lib/libgridsite.so.$(MINOR_VERSION) - cp -f doxygen/index.html \ - $(prefix)/share/doc/gridsite-$(PATCH_VERSION)/doxygen-index.html - cp -f doxygen/* $(prefix)/share/doc/gridsite-$(PATCH_VERSION) - cp -f ../CHANGES ../README ../INSTALL ../LICENSE ../VERSION \ - $(prefix)/share/doc/gridsite-$(PATCH_VERSION) - cp -f ../doc/*.html ../doc/*.conf ../doc/*.1 ../doc/*.sh \ - $(prefix)/share/doc/gridsite-$(VERSION) - cp -f ../doc/*.1 $(prefix)/share/man/man1 - gzip -f $(prefix)/share/man/man1/*.1 - cd ../doc ; for i in *.1 ; do ../src/roffit < $$i \ - > $(prefix)/share/doc/gridsite-$(VERSION)/$$i.html ; done - cp -f htcp $(prefix)/bin - ln -sf htcp $(prefix)/bin/htls - ln -sf htcp $(prefix)/bin/htll - ln -sf htcp $(prefix)/bin/htrm - ln -sf htcp $(prefix)/bin/htmkdir - cp -f mod_gridsite.so $(prefix)/lib/httpd/modules - -# -# Distributions -# - -# source files tarball -dist: - mkdir -p ../gridsite-$(PATCH_VERSION)/src \ - ../gridsite-$(PATCH_VERSION)/doc \ - ../gridsite-$(PATCH_VERSION)/interface - cp -f ../VERSION ../README ../LICENSE ../CHANGES ../INSTALL \ - ../gridsite-$(PATCH_VERSION) - cp -f Makefile grst*.c htproxyput.c proxyput-example.c htcp.c \ - urlencode.c findproxyfile.c gaclexample.c mod_gridsite.c \ - delegation.h grst_admin.h mod_ssl-private.h \ - roffit gridsite.spec \ - Doxyfile doxygen.css doxyheader.html \ - ../gridsite-$(PATCH_VERSION)/src - cp -f ../doc/*.html ../doc/*.1 ../doc/*.conf ../doc/*.sh \ - ../gridsite-$(PATCH_VERSION)/doc - cp -f ../interface/*.h \ - ../gridsite-$(PATCH_VERSION)/interface - cd .. ; tar zcvf gridsite-$(PATCH_VERSION).src.tar.gz \ - gridsite-$(PATCH_VERSION) - rm -Rf ../gridsite-$(PATCH_VERSION) - - -# binary tarball distribution for htcp users -htcp-bin: htcp - mkdir -p ../htcp-bin-$(PATCH_VERSION)/bin \ - ../htcp-bin-$(PATCH_VERSION)/man/man1 - cp -f ../doc/README.htcp-bin ../htcp-bin-$(PATCH_VERSION) - cp -f htcp ../htcp-bin-$(PATCH_VERSION)/bin - cp -f ../doc/htcp.1 ../doc/htrm.1 ../doc/htls.1 ../doc/htll.1 \ - ../doc/htmkdir.1 ../htcp-bin-$(PATCH_VERSION)/man/man1 - ln -sf htcp ../htcp-bin-$(PATCH_VERSION)/bin/htls - ln -sf htcp ../htcp-bin-$(PATCH_VERSION)/bin/htll - ln -sf htcp ../htcp-bin-$(PATCH_VERSION)/bin/htrm - ln -sf htcp ../htcp-bin-$(PATCH_VERSION)/bin/htmkdir - cd ../htcp-bin-$(VERSION) ; tar zcvf ../htcp-$(VERSION).bin.tar.gz . - rm -Rf ../htcp-bin-$(PATCH_VERSION) - -# RPM targets: build and RPMs go into subdirectories of ../RPMTMP/ -rpm: dist gridsite.spec - rm -Rf $(MYRPMDIR)/BUILDROOT $(MYRPMDIR)/BUILD - mkdir -p $(MYRPMDIR)/SOURCES $(MYRPMDIR)/SPECS $(MYRPMDIR)/BUILD \ - $(MYRPMDIR)/SRPMS $(MYRPMDIR)/RPMS/i386 $(MYRPMDIR)/BUILDROOT - cp -f ../gridsite-$(PATCH_VERSION).src.tar.gz $(MYRPMDIR)/SOURCES - cp -f gridsite.spec $(MYRPMDIR)/SPECS - export MYPREFIX=/usr ; export MYVERSION=$(PATCH_VERSION) ; \ - $(RPMCMD) --define "_topdir $(MYRPMDIR)" \ - -ba --buildroot $(MYRPMDIR)/BUILDROOT gridsite.spec - - -wtf: - pwd - printenv - ls -l - ls -lR /usr/local/ - diff --git a/org.gridsite.core/src/delegation.h b/org.gridsite.core/src/delegation.h deleted file mode 100644 index e612498..0000000 --- a/org.gridsite.core/src/delegation.h +++ /dev/null @@ -1,12 +0,0 @@ -//gsoap ns service name: delegation -//gsoap ns service style: rpc -//gsoap ns service encoding: encoded -//gsoap ns service namespace: http://www.gridsite.org/ns/delegation.wsdl -//gsoap ns service location: http://localhost/delegserver.cgi - -struct ns__putProxyResponse { } ; - -//gsoap ns schema namespace: urn:delegation -int ns__getProxyReq(char *delegationID, char **request); -int ns__putProxy(char *delegationID, char *proxy, - struct ns__putProxyResponse *unused); diff --git a/org.gridsite.core/src/doxygen.css b/org.gridsite.core/src/doxygen.css deleted file mode 100644 index 97ebc25..0000000 --- a/org.gridsite.core/src/doxygen.css +++ /dev/null @@ -1,49 +0,0 @@ -H1 { text-align: center; } -CAPTION { font-weight: bold } -A.qindex {} -A.qindexRef {} -A.el { text-decoration: none; font-weight: bold } -A.elRef { font-weight: bold } -A.code { text-decoration: none; font-weight: normal; color: #4444ee } -A.codeRef { font-weight: normal; color: #4444ee } -A:hover { text-decoration: none; background-color: #f2f2ff } -DL.el { margin-left: -1cm } -DIV.fragment { width: 100%; border: none; background-color: #eeeeee } -DIV.ah { background-color: black; font-weight: bold; color: #ffffff; margin-bottom: 3px; margin-top: 3px } -TD.md { background-color: #f2f2ff; font-weight: bold; } -TD.mdname1 { background-color: #f2f2ff; font-weight: bold; color: #602020; } -TD.mdname { background-color: #f2f2ff; font-weight: bold; color: #602020; width: 600px; } -DIV.groupHeader { margin-left: 16px; margin-top: 12px; margin-bottom: 6px; font-weight: bold } -DIV.groupText { margin-left: 16px; font-style: italic; font-size: smaller } -XXBODY { background: white } -TD.indexkey { - background-color: #eeeeff; - font-weight: bold; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px -} -TD.indexvalue { - background-color: #eeeeff; - font-style: italic; - padding-right : 10px; - padding-top : 2px; - padding-left : 10px; - padding-bottom : 2px; - margin-left : 0px; - margin-right : 0px; - margin-top : 2px; - margin-bottom : 2px -} -span.keyword { color: #008000 } -span.keywordtype { color: #604020 } -span.keywordflow { color: #e08000 } -span.comment { color: #800000 } -span.preprocessor { color: #806020 } -span.stringliteral { color: #002080 } -span.charliteral { color: #008080 } diff --git a/org.gridsite.core/src/doxyheader.html b/org.gridsite.core/src/doxyheader.html deleted file mode 100644 index af78b52..0000000 --- a/org.gridsite.core/src/doxyheader.html +++ /dev/null @@ -1 +0,0 @@ -

GridSite Version 1.1.x diff --git a/org.gridsite.core/src/findproxyfile.c b/org.gridsite.core/src/findproxyfile.c deleted file mode 100644 index 4485cc5..0000000 --- a/org.gridsite.core/src/findproxyfile.c +++ /dev/null @@ -1,122 +0,0 @@ -/* - Copyright (c) 2002-4, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef VERSION -#define VERSION "0.0.0" -#endif - -#define _GNU_SOURCE - -#include -#include -#include -#include - -#include - -#include "gridsite.h" - -void printsyntax(char *argv0) -{ - char *p; - - p = rindex(argv0, '/'); - if (p != NULL) ++p; - else p = argv0; - - fprintf(stderr, "%s [--outsidecache] [--proxycache=PATH] " - "[--delegation-id=DELEGATION-ID] [--user-dn=USER-DN]\n" - "(Version: %s)\n", p, VERSION); -} - -#define GRST_PROXY_CACHE "/var/www/proxycache" - -int main(int argc, char *argv[]) -{ - char *delegation_id = "_", *proxycache = "", *user_dn = "", - *proxyfile = NULL; - int c, outsidecache = 0, verbose = 0, option_index; - struct option long_options[] = { {"verbose", 0, 0, 'v'}, - {"outsidecache", 0, 0, 0}, - {"proxycache", 1, 0, 0}, - {"delegation-id", 1, 0, 0}, - {"user-dn", 1, 0, 0}, - {0, 0, 0, 0} }; - - if (argc == 1) - { - printsyntax(argv[0]); - return 0; - } - - while (1) - { - option_index = 0; - - c = getopt_long(argc, argv, "v", long_options, &option_index); - - if (c == -1) break; - else if (c == 0) - { - if (option_index == 1) outsidecache = 1; - else if (option_index == 2) proxycache = optarg; - else if (option_index == 3) delegation_id = optarg; - else if (option_index == 4) user_dn = optarg; - } - else if (c == 'v') ++verbose; - } - - if (*user_dn != '\0') /* try to find in proxy cache */ - { - if ((proxycache == NULL) || (*proxycache == '\0')) - proxycache = getenv("GRST_PROXY_CACHE"); - - if ((proxycache == NULL) || (*proxycache == '\0')) - proxycache = GRST_PROXY_CACHE; - - proxyfile = GRSTx509CachedProxyFind(proxycache, delegation_id, user_dn); - } - - if (((proxyfile == NULL) || (*proxyfile == '\0')) && outsidecache) - { - proxyfile = GRSTx509FindProxyFileName(); - } - - if ((proxyfile != NULL) && (*proxyfile != '\0')) - { - puts(proxyfile); - return 0; - } - - fputs("No proxy file found\n", stderr); - - return 1; -} diff --git a/org.gridsite.core/src/gaclexample.c b/org.gridsite.core/src/gaclexample.c deleted file mode 100644 index 5ad29b7..0000000 --- a/org.gridsite.core/src/gaclexample.c +++ /dev/null @@ -1,147 +0,0 @@ -/* - Copyright (c) 2002-3, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/*---------------------------------------------------------------* - * For more about GridSite: http://www.gridsite.org/ * - *---------------------------------------------------------------*/ - -/* - Example program using GACL - - Build with: - - gcc -o gaclexample gaclexample.c -L. -I. -lgridsite -lxml2 -lz -lm -*/ - -#include -#include -#include -#include - -int main() -{ - GRSTgaclCred *cred, *usercred; - GRSTgaclEntry *entry; - GRSTgaclAcl *acl1, *acl2; - GRSTgaclUser *user; - GRSTgaclPerm perm0, perm1, perm2; - FILE *fp; - - /* must initialise GACL before using it */ - - GRSTgaclInit(); - - /* build up an ACL, starting with a credential */ - - cred = GRSTgaclCredNew("person"); - - GRSTgaclCredAddValue(cred, "dn", "/O=Grid/CN=Mr Grid Person"); - - /* create an entry to put it in */ - - entry = GRSTgaclEntryNew(); - - /* add the credential to it */ - - GRSTgaclEntryAddCred(entry, cred); - - /* add another credential */ - - cred = GRSTgaclCredNew("dn-list"); - GRSTgaclCredAddValue(cred, "url", "example-dn-list"); - GRSTgaclEntryAddCred(entry, cred); - - fp = fopen("example-dn-list", "w"); - fputs("/O=Grid/CN=Mr Grid Person\n", fp); - fclose(fp); - - /* associate some permissions and denials to the credential */ - - GRSTgaclEntryAllowPerm( entry, GRST_PERM_READ); - GRSTgaclEntryAllowPerm( entry, GRST_PERM_WRITE); - GRSTgaclEntryAllowPerm( entry, GRST_PERM_ADMIN); - GRSTgaclEntryDenyPerm( entry, GRST_PERM_ADMIN); - GRSTgaclEntryDenyPerm( entry, GRST_PERM_LIST); - - perm0 = GRST_PERM_READ | GRST_PERM_WRITE; - - printf("test perm should be %d\n", perm0); - - /* create a new ACL and add the entry to it */ - - acl1 = GRSTgaclAclNew(); - - GRSTgaclAclAddEntry(acl1, entry); - - /* create a GRSTgaclUser to compare with the ACL */ - - usercred = GRSTgaclCredNew("person"); - - GRSTgaclCredAddValue(usercred, "dn", "/O=Grid/CN=Mr Grid Person"); - - user = GRSTgaclUserNew(usercred); - - GRSTgaclUserSetDNlists(user, getcwd(NULL, 0)); - printf("DN Lists dir %s\n", getcwd(NULL, 0)); - -// putenv("GRST_DN_LISTS=."); - - perm1 = GRSTgaclAclTestUser(acl1, user); - - printf("test /O=Grid/CN=Mr Grid Person in acl = %d\n", perm1); - - /* print and save the whole ACL */ - - GRSTgaclAclPrint(acl1, stdout); - - GRSTgaclAclSave(acl1, "example.gacl"); - - puts("gridacl.out saved"); - - puts(""); - - /* load the ACL back off the disk, print and test it */ - - acl2 = GRSTgaclAclLoadFile("example.gacl"); - - puts("gridacl.out loaded"); - - if (acl2 != NULL) GRSTgaclAclPrint(acl2, stdout); else puts("acl2 is NULL"); - - perm2 = GRSTgaclAclTestUser(acl2, user); - - printf("test /O=Grid/CN=Mr Grid Person in acl = %d\n", perm2); - - if (perm1 != perm0) return 1; - if (perm2 != perm0) return 2; - - return 0; -} diff --git a/org.gridsite.core/src/gridsite.spec b/org.gridsite.core/src/gridsite.spec deleted file mode 100644 index 877f25d..0000000 --- a/org.gridsite.core/src/gridsite.spec +++ /dev/null @@ -1,78 +0,0 @@ -Name: gridsite -Version: %(echo ${MYVERSION:-1.1.x}) -Release: 2 -Summary: GridSite -Copyright: Modified BSD -Group: System Environment/Daemons -Source: %{name}-%{version}.src.tar.gz -Prefix: %(echo ${MYPREFIX:-/usr}) -URL: http://www.gridsite.org/ -Vendor: GridPP -#Requires: libxml2,curl-ssl,mod_ssl -#Buildrequires: libxml2-devel,curl-ssl-devel,httpd-devel -Packager: Andrew McNab - -%description -GridSite adds GSI, VOMS and GACL support to Apache 2.0 (mod_gridsite), -a library for manipulating these technologies (libgridsite), and CGI -programs for interactive management of HTTP(S) servers (gridsite-admin.cgi) - -See %(echo ${MYPREFIX:-/usr})/share/doc/gridsite-%{version} and -http://www.gridsite.org/ for details. - -%package -n htcp -Group: Applications/Internet -Summary: HTTP(S) read/write client -#Requires: curl-ssl - -%description -n htcp -htcp is a client to fetch files or directory listings from remote -servers using HTTP or HTTPS, or to put or delete files or directories -onto remote servers using HTTPS. htcp is similar to scp(1), but uses -HTTP/HTTPS rather than ssh as its transfer protocol. - -%prep - -%setup - -%build -cd src -make prefix=$RPM_BUILD_ROOT/%(echo ${MYPREFIX:-/usr}) - -%install -cd src -make install prefix=$RPM_BUILD_ROOT/%(echo ${MYPREFIX:-/usr}) - -%post -/sbin/ldconfig -ln -sf %(echo ${MYPREFIX:-/usr})/share/doc/gridsite-%{version} \ - %(echo ${MYPREFIX:-/usr})/share/doc/gridsite - -%postun -rm -f %(echo ${MYPREFIX:-/usr})/share/doc/gridsite - -%files -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/lib/libgridsite.so.%{version} -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/lib/libgridsite.so -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/bin/urlencode -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/bin/findproxyfile -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/share/doc/gridsite-%{version} -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/share/man/man1/urlencode.1.gz -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/share/man/man1/findproxyfile.1.gz -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/include/gridsite.h -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/include/gridsite-gacl.h -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/lib/libgridsite.a -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/lib/httpd/modules/mod_gridsite.so -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/sbin/real-gridsite-admin.cgi - -%files -n htcp -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/bin/htcp -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/bin/htls -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/bin/htll -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/bin/htrm -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/bin/htmkdir -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/share/man/man1/htcp.1.gz -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/share/man/man1/htrm.1.gz -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/share/man/man1/htls.1.gz -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/share/man/man1/htll.1.gz -%attr(-, root, root) %(echo ${MYPREFIX:-/usr})/share/man/man1/htmkdir.1.gz diff --git a/org.gridsite.core/src/grst-delegation.c b/org.gridsite.core/src/grst-delegation.c deleted file mode 100644 index 2a8a9b2..0000000 --- a/org.gridsite.core/src/grst-delegation.c +++ /dev/null @@ -1,295 +0,0 @@ -/* - Copyright (c) 2002-4, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/*---------------------------------------------------------------------------* - * This program is part of GridSite: http://www.gridpp.ac.uk/authz/gridsite/ * - *---------------------------------------------------------------------------*/ - -#ifndef VERSION -#define VERSION "0.0.1" -#endif - -#define _GNU_SOURCE -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -/* #include */ - -#include "gridsite.h" - -#include "soapH.h" -#include "delegation.nsmap" - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#define GRST_KEYSIZE 512 -#define GRST_PROXYCACHE "/../proxycache/" -#define GRST_SUPPORT_G_HTTPS - -#ifdef GRST_SUPPORT_G_HTTPS -void GRSThttpError(char *status) -{ - printf("Status: %s\n", status); - printf("Server-CGI: GridSite %s\n", VERSION); - printf("Content-Length: %d\n", 2 * strlen(status) + 58); - puts("Content-Type: text/html\n"); - - printf("%s\n", status); - printf("

%s

\n", status); - - exit(0); -} - -int GRSTmethodPutProxy(char *delegation_id, char *user_dn) -/* return 0 on success; non-zero on error */ -{ - int c, len = 0, i; - char *docroot, *contentlen, *contenttype, *proxychain, *proxydir; - FILE *fp; - - if (((contenttype = getenv("CONTENT_TYPE")) == NULL) || - (strcmp(contenttype, "application/x-x509-user-cert-chain") != 0)) - return 2; - - contentlen = getenv("CONTENT_LENGTH"); - if (contentlen == NULL) return 2; - len = atoi(contentlen); - - if ((delegation_id == NULL) || (*delegation_id == '\0')) - delegation_id = "_"; - - docroot = getenv("DOCUMENT_ROOT"); - asprintf(&proxydir, "%s/%s", docroot, GRST_PROXYCACHE); - - if ((user_dn == NULL) || (user_dn[0] == '\0') || - (GRSTx509CacheProxy(proxydir, delegation_id, user_dn, proxychain) - != GRST_RET_OK)) - { - return GRST_RET_FAILED; - } - - free(proxydir); - - return GRST_RET_OK; -} -#endif - -int main(int argn, char *argv[]) -{ - char *docroot, *method, *request, *p, *client_dn, *user_dn, - *delegation_id, *reqtxt, *proxydir; - struct soap soap; - - method = getenv("REQUEST_METHOD"); - if (strcmp(method, "POST") == 0) - { - soap_init(&soap); - soap_serve(&soap); /* CGI application */ - return 0; - } - -#ifdef GRST_SUPPORT_G_HTTPS - docroot = getenv("DOCUMENT_ROOT"); - - request = strdup(getenv("REQUEST_URI")); - p = index(request, '?'); - if (p != NULL) *p = '\0'; - - - /* non HTTP POST methods - ie special G-HTTPS methods */ - - delegation_id = getenv("HTTP_DELEGATION_ID"); - if ((delegation_id == NULL) || (*delegation_id == '\0')) delegation_id = "_"; - - user_dn = NULL; - client_dn = getenv("SSL_CLIENT_S_DN"); - if (client_dn != NULL) - { - user_dn = strdup(client_dn); - - /* we assume here that mod_ssl has verified proxy chain already ... */ - - p = strstr(user_dn, "/CN=proxy"); - if (p != NULL) *p = '\0'; - - p = strstr(user_dn, "/CN=limited proxy"); - if (p != NULL) *p = '\0'; - } - - if (user_dn == NULL) /* all methods require client auth */ - { - GRSThttpError("403 Forbidden"); - } - else if (strcmp(method, "GET-PROXY-REQ") == 0) - { - docroot = getenv("DOCUMENT_ROOT"); - asprintf(&proxydir, "%s/%s", docroot, GRST_PROXYCACHE); - - if (GRSTx509MakeProxyRequest(&reqtxt, proxydir, - delegation_id, user_dn) == 0) - { - puts("Status: 200 OK"); - puts("Content-Type: application/x-x509-cert-request"); - printf("Content-Length: %d\n\n", strlen(reqtxt)); - fputs(reqtxt, stdout); - free(proxydir); - return 0; - } - - puts("Status: 500 Internal Server Error\n"); - free(proxydir); - return 0; - } - else if (strcmp(method, "PUT-PROXY-CERT") == 0) - { - if (GRSTmethodPutProxy(delegation_id, user_dn) == 0) - { - puts("Status: 200 OK\n"); - return 0; - } - - puts("Status: 500 Internal Server Error\n"); - return 0; - } - else - { - GRSThttpError("501 Method Not Implemented"); - } -#endif -} - -int ns__getProxyReq(struct soap *soap, char *delegation_id, - char **request) -{ - char *p, *client_dn, *user_dn, *docroot, *proxydir; - - user_dn = NULL; - client_dn = getenv("SSL_CLIENT_S_DN"); - if (client_dn != NULL) - { - user_dn = strdup(client_dn); - - /* we assume here that mod_ssl has verified proxy chain already ... */ - - p = strstr(user_dn, "/CN=proxy"); - if (p != NULL) *p = '\0'; - - p = strstr(user_dn, "/CN=limited proxy"); - if (p != NULL) *p = '\0'; - } - - if ((delegation_id == NULL) || (*delegation_id == '\0')) delegation_id = "_"; - - docroot = getenv("DOCUMENT_ROOT"); - asprintf(&proxydir, "%s/%s", docroot, GRST_PROXYCACHE); - - if ((user_dn != NULL) && (user_dn[0] != '\0') && - (GRSTx509MakeProxyRequest(request, proxydir, - delegation_id, user_dn) == 0)) - { - return SOAP_OK; - } - - return SOAP_ERR; -} - -int ns__putProxy(struct soap *soap, char *delegation_id, - char *proxy, - struct ns__putProxyResponse *unused) -{ - int fd, c, len = 0, i; - char *docroot, *proxydir, *p, *client_dn, *user_dn; - - user_dn = NULL; - client_dn = getenv("SSL_CLIENT_S_DN"); - if (client_dn != NULL) - { - user_dn = strdup(client_dn); - - /* we assume here that mod_ssl has verified proxy chain already ... */ - - p = strstr(user_dn, "/CN=proxy"); - if (p != NULL) *p = '\0'; - - p = strstr(user_dn, "/CN=limited proxy"); - if (p != NULL) *p = '\0'; - } - - if ((delegation_id == NULL) || (*delegation_id == '\0')) - delegation_id = "_"; - - docroot = getenv("DOCUMENT_ROOT"); - asprintf(&proxydir, "%s/%s", docroot, GRST_PROXYCACHE); - - if ((user_dn == NULL) || (user_dn[0] == '\0') || - (GRSTx509CacheProxy(proxydir, delegation_id, user_dn, proxy) - != GRST_RET_OK)) - { - return SOAP_ERR; - } - - return SOAP_OK; -} - diff --git a/org.gridsite.core/src/grst_admin.h b/org.gridsite.core/src/grst_admin.h deleted file mode 100644 index cddc415..0000000 --- a/org.gridsite.core/src/grst_admin.h +++ /dev/null @@ -1,57 +0,0 @@ -/* - Copyright (c) 2002-3, Andrew McNab and Shiv Kaushal, - University of Manchester. All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/*------------------------------------------------------------------* - * This program is part of GridSite: http://www.gridsite.org/ * - *------------------------------------------------------------------*/ - -void GRSThttpError(char *); -void adminfooter(GRSThttpBody *, char *, char *, char *, char *); -int GRSTstrCmpShort(char *, char *); -char *makevfilename(char *, size_t, char *); - -/*CGI GACL - Edit interface functions*/ -void show_acl(int admin, GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void new_entry_form(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void new_entry(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void del_entry(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void edit_entry_form(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void edit_entry(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void add_cred_form(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void add_cred(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void del_cred(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void del_entry_sure(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void del_cred_sure(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); - -/*Functions producing messages*/ -//void error(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void admin_continue(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file, GRSThttpBody *bp); - diff --git a/org.gridsite.core/src/grst_admin_file.c b/org.gridsite.core/src/grst_admin_file.c deleted file mode 100644 index f89a004..0000000 --- a/org.gridsite.core/src/grst_admin_file.c +++ /dev/null @@ -1,1571 +0,0 @@ -/* - Copyright (c) 2002-3, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/*------------------------------------------------------------------* - * This program is part of GridSite: http://www.gridsite.org/ * - *------------------------------------------------------------------*/ - -#ifndef VERSION -#define VERSION "x.x.x" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// when porting: remember that sendfile() is very OS-specific! -#include - -#include - -#include "grst_admin.h" - -char *storeuploadfile(char *boundary, int *bufferused) -{ -// rewrite this to copy whole POSTed stdin HTTP body to disk then -// mmap() and pick apart? How to deal with 100MB uploaded files, say? - - char *filebuffer = NULL; - int bufferlen = 0, c, boundarylen; - - *bufferused = 0; - boundarylen = strlen(boundary); - - while ((c = getchar()) != EOF) - { - if (*bufferused > 1024*1024*100) return NULL; - - ++(*bufferused); - - if (*bufferused > bufferlen) - { - bufferlen = bufferlen + 1000; - filebuffer = realloc(filebuffer, (size_t) bufferlen); - } - - filebuffer[*bufferused - 1] = c; - - if ( (*bufferused >= boundarylen + 4) && - (boundary[boundarylen-1] == c) && - (boundary[boundarylen-2] == filebuffer[*bufferused - 2]) && - (strncmp(boundary, &filebuffer[*bufferused - boundarylen], - boundarylen) == 0)) - { - *bufferused = *bufferused - boundarylen - 4; - - if (filebuffer == NULL) return strdup(""); - else return filebuffer; - } - } - - return NULL; -} - -void uploadfile(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *dir_uri, char *admin_file) -{ - char *boundary, *p, oneline[200], *filename = NULL, - tmpfilename[256], *filebuffer = NULL, *filepath, - *vfile, *dir_path_vfile; - int mimestate, bufferused = 0, itworked = 0; - FILE *fp; - GRSThttpBody bp; - -#define MIMESTUNKNOWN 1 -#define MIMESTUPLOAD 2 -#define MIMESTFILENM 3 - - if (!GRSTgaclPermHasWrite(perm)) GRSThttpError("403 Forbidden"); - - p = getenv("CONTENT_TYPE"); - boundary = &p[30]; - - mimestate = MIMESTUNKNOWN; - - while (fgets(oneline, sizeof(oneline), stdin) != NULL) - { - if (*oneline == 13) // MIME has CR/LF line breaks, CR=13 - { - if (mimestate == MIMESTUPLOAD) - { - filebuffer = storeuploadfile(boundary, &bufferused); - mimestate = MIMESTUNKNOWN; - } - else if (mimestate == MIMESTFILENM) - { - fgets(tmpfilename, sizeof(tmpfilename), stdin); - if (*tmpfilename != 13) - { - p = index(tmpfilename, 13); - *p = '\0'; - filename = strdup(tmpfilename); - } - mimestate = MIMESTUNKNOWN; - } - } - else if (GRSTstrCmpShort(oneline, - "Content-Disposition: form-data; name=\"uploadfile\"; filename=\"") - == 0) - { - mimestate = MIMESTUPLOAD; - if (filename == NULL) - { - filename = strdup(&oneline[61]); - - p = rindex(&oneline[61], '\\'); - if (p != NULL) { ++p ; filename = p; } - - p = rindex(&oneline[61], '/'); - if (p != NULL) { ++p ; filename = p; } - - p = index(filename, '"'); - if (p != NULL) *p = '\0'; - } - } - else if (GRSTstrCmpShort(oneline, - "Content-Disposition: form-data; name=\"file\"") == 0) - { - mimestate = MIMESTFILENM; - } - } - - if ((filebuffer != NULL) && (bufferused >= 0)) - { - if (filename == NULL) GRSThttpError("403 Forbidden"); - else if ((index(filename, '/') != NULL) || - (strcmp(filename, GRST_ACL_FILE) == 0)) - { - puts("Status: 403 Forbidden filename\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp,"Forbidden filename %s\n", filename); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Forbidden filename %s

\n", - filename); - - GRSThttpPrintf(&bp, - "

New file names cannot include slashes " - "or use the reserved ACL name, %s\n", GRST_ACL_FILE); - - GRSThttpPrintf(&bp,"

" - "Return to " - "directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); - return; - } - else - { - vfile = makevfilename(filename, bufferused, dn); - asprintf(&dir_path_vfile, "%s/%s", dir_path, vfile); - - fp = fopen(dir_path_vfile, "w"); - if (fp != NULL) - { - if ((fwrite(filebuffer, - sizeof(char), bufferused, fp) == bufferused) && - (fclose(fp) == 0)) - { - asprintf(&filepath, "%s/%s", dir_path, filename); - - unlink(filepath); /* this can fail ok */ - - itworked = (link(dir_path_vfile, filepath) == 0); - } - } - } - - free((void *) filebuffer); - } - - if (itworked) - { - printf("Status: 302 Moved Temporarily\nContent-Length: 0\n" - "Location: %s%s?cmd=managedir\n\n", dir_uri, admin_file); - return; - } - - puts("Status: 500 Failed trying to upload\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp, "Failed to upload\n"); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Failed to upload

\n"); - - GRSThttpPrintf(&bp, "

GridSite considers you are authorized " - "to upload the file, but the upload failed. This is " - "probably a web server or operating system level " - "misconfiguration. Consult the site administrator."); - - GRSThttpPrintf(&bp,"

" - "Return to " - "directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); -} - -void deletefileaction(char *dn, GRSTgaclPerm perm, char *help_uri, - char *dir_path, char *file, char *dir_uri, - char *admin_file) -{ - int fd, numfiles; - char *dir_path_file, *dir_path_vfile, *p, *vfile, *dnlistsuri, - *fulluri, *server_name, *realfile; - struct stat statbuf; - GRSThttpBody bp; - struct dirent *subdirfile_ent; - DIR *subDIR; - - if (((strcmp(file, GRST_ACL_FILE) != 0) && !GRSTgaclPermHasWrite(perm)) || - ((strcmp(file, GRST_ACL_FILE) == 0) && !GRSTgaclPermHasAdmin(perm))) - GRSThttpError("403 Forbidden"); - - dnlistsuri = getenv("GRST_DN_LISTS_URI"); - if (dnlistsuri == NULL) dnlistsuri = getenv("REDIRECT_GRST_DN_LISTS_URI"); - - if ((dnlistsuri != NULL) && - (strncmp(dnlistsuri, dir_uri, strlen(dnlistsuri)) == 0)) - realfile = GRSThttpUrlEncode(file); - else if (index(file, '/') != NULL) GRSThttpError("403 Forbidden"); - else realfile = file; - - dir_path_file = malloc(strlen(dir_path) + strlen(realfile) + 2); - - strcpy(dir_path_file, dir_path); - strcat(dir_path_file, "/"); - strcat(dir_path_file, realfile); - - if ((stat(dir_path_file, &statbuf) == 0) && S_ISDIR(statbuf.st_mode)) - { - subDIR = opendir(dir_path_file); - if (subDIR == NULL) numfiles = 99; /* stop deletion */ - else - { - numfiles = 0; - while ((subdirfile_ent = readdir(subDIR)) != NULL) - if (subdirfile_ent->d_name[0] != '.') ++numfiles; - else if (strncmp(subdirfile_ent->d_name, - GRST_ACL_FILE, - sizeof(GRST_ACL_FILE)) == 0) ++numfiles; - closedir(subDIR); - } - - if (numfiles == 0) - { - vfile = makevfilename(file, 0, dn); - dir_path_vfile = malloc(strlen(dir_path) + strlen(vfile) + 2); - strcpy(dir_path_vfile, dir_path); - strcat(dir_path_vfile, "/"); - strcat(dir_path_vfile, vfile); - - if (rename(dir_path_file, dir_path_vfile) == 0) - { - printf("Status: 302 Moved Temporarily\nContent-Length: 0\n" - "Location: %s%s?cmd=managedir\n\n", dir_uri, admin_file); - return; - } - } - } - else if (unlink(dir_path_file) == 0) - { - if (strcmp(file, GRST_ACL_FILE) != 0) - { - vfile = makevfilename(file, 0, dn); - dir_path_file = malloc(strlen(dir_path) + strlen(vfile) + 2); - strcpy(dir_path_file, dir_path); - strcat(dir_path_file, "/"); - strcat(dir_path_file, vfile); - - fd = open(dir_path_file, O_WRONLY | O_CREAT); - if (fd != -1) close(fd); - } - - printf("Status: 302 Moved Temporarily\nContent-Length: 0\n" - "Location: %s%s?cmd=managedir\n\n", dir_uri, admin_file); - - return; - } - - puts("Status: 500 Failed trying to delete\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp, "Error deleting %s%s\n", dir_uri, file); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Error deleting %s%s

\n", - dir_uri, file); - - GRSThttpPrintf(&bp, "

GridSite considers you are authorized " - "to delete %s, but the delete failed. This is " - "probably a web server or operating system level " - "misconfiguration. Consult the site administrator.", - file); - - GRSThttpPrintf(&bp,"

" - "Return to " - "directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); -} - -void deletefileform(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - GRSThttpBody bp; - - if (!GRSTgaclPermHasWrite(perm)) GRSThttpError("403 Forbidden"); - - puts("Status: 200 OK\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp, "Delete %s\n", file); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Delete %s

\n", file); - - GRSThttpPrintf(&bp,"
\n",dir_uri,admin_file); - GRSThttpPrintf(&bp,"

Do you really want to delete %s?", file); - GRSThttpPrintf(&bp,"

\n", file); - GRSThttpPrintf(&bp,"\n", file); - GRSThttpPrintf(&bp,"\n"); - GRSThttpPrintf(&bp,"
\n"); - - GRSThttpPrintf(&bp,"

Or " - "return to " - "directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); -} - -void renameform(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - GRSThttpBody bp; - - if (!GRSTgaclPermHasWrite(perm)) GRSThttpError("403 Forbidden"); - - puts("Status: 200 OK\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp, "Rename %s\n", file); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Rename %s%s

\n", dir_uri, file); - - GRSThttpPrintf(&bp,"
\n",dir_uri,admin_file); - GRSThttpPrintf(&bp,"

What do you want to rename %s to?

", file); - GRSThttpPrintf(&bp,"\n", file); - GRSThttpPrintf(&bp,"

New name: \n", file); - GRSThttpPrintf(&bp,"\n"); - GRSThttpPrintf(&bp,"\n"); - GRSThttpPrintf(&bp,"

\n"); - - GRSThttpPrintf(&bp,"

Or " - "return to " - "directory listing\n", dir_uri, admin_file, dir_uri); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); -} - -void editfileaction(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - char *pagetext, *dir_path_file, *vfile, *dir_path_vfile, - *dnlistsuri, *server_name, *fulluri, *realfile; - FILE *fp; - GRSThttpBody bp; - - if (!GRSTgaclPermHasWrite(perm) || (strcmp(file, GRST_ACL_FILE) == 0)) - GRSThttpError("403 Forbidden"); - - dnlistsuri = getenv("GRST_DN_LISTS_URI"); - if (dnlistsuri == NULL) dnlistsuri = getenv("REDIRECT_GRST_DN_LISTS_URI"); - - if ((dnlistsuri != NULL) && - (strncmp(dnlistsuri, dir_uri, strlen(dnlistsuri)) == 0)) - { - realfile = GRSThttpUrlEncode(file); - - if (realfile[0] == '.') GRSThttpError("403 Forbidden"); - } - else if (index(file, '/') != NULL) GRSThttpError("403 Forbidden"); - else realfile = file; - - asprintf(&dir_path_file, "%s/%s", dir_path, realfile); - - pagetext = GRSThttpGetCGI("pagetext"); - vfile = makevfilename(file, strlen(pagetext), dn); - asprintf(&dir_path_vfile, "%s/%s", dir_path, vfile); - - fp = fopen(dir_path_vfile, "w"); - if (fp == NULL) - { - puts("Status: 500 Failed trying to write\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp,"Error writing %s%s\n", dir_uri, file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Error writing %s%s

\n", - dir_uri, file); - - GRSThttpPrintf(&bp, - "

GridSite considers you are authorized " - "to write the file, but the write failed. This is " - "probably a web server or operating system level " - "misconfiguration. Consult the site administrator."); - - GRSThttpPrintf(&bp,"

" - "Return to " - "directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); - return; - } - - fwrite(pagetext, strlen(pagetext), sizeof(char), fp); - - fclose(fp); - - unlink(dir_path_file); - - if (link(dir_path_vfile,dir_path_file) != 0) GRSThttpError("403 Forbidden"); - - if ((strlen(file) > 7) && (strcmp(&file[strlen(file) - 5], ".html") == 0)) - printf("Status: 302 Moved Temporarily\nContent-Length: 0\n" - "Location: %s%s\n\n", dir_uri, file); - else printf("Status: 302 Moved Temporarily\nContent-Length: 0\n" - "Location: %s%s?cmd=managedir\n\n", dir_uri, admin_file); -} - -void create_acl(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - int fd; - char *tmpgacl, *newgacl; - GRSTgaclAcl *acl; - FILE *fp; - GRSThttpBody bp; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError("403 Forbidden"); - - asprintf(&tmpgacl, "%s/.tmp.XXXXXX", dir_path); - asprintf(&newgacl, "%s/%s", dir_path, GRST_ACL_FILE); - - if (((acl = GRSTgaclAclLoadforFile(dir_path)) != NULL) && - ((fd = mkstemp(tmpgacl)) != -1) && - ((fp = fdopen(fd, "w+")) != NULL) && - GRSTgaclAclPrint(acl, fp) && - (fclose(fp) == 0) && - (rename(tmpgacl, newgacl) == 0)) - { - printf("Status: 302 Moved Temporarily\nContent-Length: 0\n" - "Location: %s%s?cmd=managedir\n\n", dir_uri, admin_file); - - free(tmpgacl); - free(newgacl); - return; - } - - puts("Status: 500 Failed trying to create\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp,"Error creating %s%s\n", dir_uri, - GRST_ACL_FILE); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Error creating %s%s

\n", - dir_uri, GRST_ACL_FILE); - - GRSThttpPrintf(&bp, "

GridSite considers you are authorized " - "to create it, but the create failed. This is " - "probably a web server or operating system level " - "misconfiguration. Consult the site administrator."); - - GRSThttpPrintf(&bp,"

" - "Return to " - "directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); - - free(tmpgacl); - free(newgacl); -} - -void renameaction(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - int len; - char *dir_path_file, *vfile, *dir_path_vfile, - *dnlistsuri, *newfile, *dir_path_newfile; - struct stat statbuf; - FILE *fp; - GRSThttpBody bp; - - if (!GRSTgaclPermHasWrite(perm) || (strcmp(file, GRST_ACL_FILE) == 0)) - GRSThttpError("403 Forbidden"); - - if (index(file, '/') != NULL) GRSThttpError("403 Forbidden"); - - dir_path_file = malloc(strlen(dir_path) + strlen(file) + 2); - strcpy(dir_path_file, dir_path); - strcat(dir_path_file, "/"); - strcat(dir_path_file, file); - - if (stat(dir_path_file, &statbuf) != 0) GRSThttpError("404 Not Found"); - - newfile = GRSThttpGetCGI("newfile"); - - if ((strcmp(newfile, GRST_ACL_FILE) == 0) || - (strcmp(newfile, file) == 0)) GRSThttpError("403 Forbidden"); - - dir_path_newfile = malloc(strlen(dir_path) + strlen(newfile) + 2); - strcpy(dir_path_newfile, dir_path); - strcat(dir_path_newfile, "/"); - strcat(dir_path_newfile, newfile); - - vfile = makevfilename(newfile, statbuf.st_size, dn); - dir_path_vfile = malloc(strlen(dir_path) + strlen(vfile) + 2); - strcpy(dir_path_vfile, dir_path); - strcat(dir_path_vfile, "/"); - strcat(dir_path_vfile, vfile); - - unlink(dir_path_newfile); /* just in case */ - - if ((link(dir_path_file, dir_path_vfile ) == 0) && - (link(dir_path_file, dir_path_newfile) == 0) && - (unlink(dir_path_file) == 0)) - { - printf("Status: 302 Moved Temporarily\nContent-Length: 0\n" - "Location: %s\n\n", dir_uri); - return; - } - - puts("Status: 500 Failed trying to rename\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp,"Error renaming %s%s\n", dir_uri, file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Error renaming %s%s

\n", - dir_uri, file); - - GRSThttpPrintf(&bp, "

GridSite considers you are authorized " - "to rename it, but the rename failed. This is " - "probably a web server or operating system level " - "misconfiguration. Consult the site administrator."); - - GRSThttpPrintf(&bp,"

" - "Return to " - "directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); -} - -void newdirectory(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - int len; - char *dir_path_file, *vfile, *dir_path_vfile, *filedup; - FILE *fp; - GRSThttpBody bp; - - if ((file[0] == '\0') || - !GRSTgaclPermHasWrite(perm) || (strcmp(file, GRST_ACL_FILE) == 0)) - GRSThttpError("403 Forbidden"); - - filedup = strdup(file); - if (filedup[strlen(filedup)-1] == '/') filedup[strlen(filedup)-1] = '\0'; - if (index(filedup, '/') != NULL) GRSThttpError("403 Forbidden"); - - dir_path_file = malloc(strlen(dir_path) + strlen(file) + 2); - strcpy(dir_path_file, dir_path); - strcat(dir_path_file, "/"); - strcat(dir_path_file, file); - - if (mkdir(dir_path_file, 0751) == 0) - { - printf("Status: 302 Moved Temporarily\nContent-Length: 0\n" - "Location: %s%s?cmd=managedir\n\n", dir_uri, admin_file); - return; - } - - puts("Status: 500 Failed trying to create\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp,"Error create %s%s\n", dir_uri, file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Error creating directory %s%s

\n", - dir_uri, file); - - GRSThttpPrintf(&bp, - "

GridSite considers you are authorized " - "to create the directory, but the creation failed. This " - "is probably a web server or operating system level " - "misconfiguration. Consult the site administrator."); - - GRSThttpPrintf(&bp,"

" - "Return to " - "parent directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); -} - -void editdnlistaction(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - int numdn = 0, ifd, ofd, numdnlines = 0, i, found; - char *dir_path_file, *dir_path_tmpfile, *realfile, - *dnlistsuri, *server_name, *fulldiruri, *p, oneline[513], - **dnlines, name[81], *add; - FILE *ofp; - struct stat statbuf; - GRSThttpBody bp; - - if (!GRSTgaclPermHasWrite(perm)) GRSThttpError("403 Forbidden"); - - dnlistsuri = getenv("GRST_DN_LISTS_URI"); - if (dnlistsuri == NULL) dnlistsuri = getenv("REDIRECT_GRST_DN_LISTS_URI"); - - server_name = getenv("SERVER_NAME"); - - if ((server_name == NULL) || - (dnlistsuri == NULL) || - (strncmp(dnlistsuri, dir_uri, strlen(dnlistsuri)) != 0)) - GRSThttpError("403 Forbidden"); - - asprintf(&fulldiruri, "https://%s%s", server_name, dir_uri); - - if ((strncmp(fulldiruri, file, strlen(fulldiruri)) != 0) && - ((strncmp(fulldiruri, file, strlen(fulldiruri) - 1) != 0) || - (strlen(fulldiruri) - 1 != strlen(file)))) - { - puts("Status: 403 Forbidden\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp,"Error writing %s\n", file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Error writing %s to %s

\n", - file, dir_uri); - - GRSThttpPrintf(&bp, "

You cannot create a DN List " - "with that prefix in this directory. Please see the " - "the GridSite User's Guide for an explanation."); - - GRSThttpPrintf(&bp,"

" - "Return to " - "directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); - return; - } - - p = GRSThttpGetCGI("numdn"); - if ((p == NULL) || (sscanf(p, "%d", &numdn) != 1)) - GRSThttpError("500 No number of DNs"); - - if (numdn > 0) - { - dnlines = malloc(sizeof(char *) * numdn); - - for (i=1; i <= numdn; ++i) - { - sprintf(name, "dn%d", i); - p = GRSThttpGetCGI(name); - - if (*p != '\0') - { - dnlines[numdnlines] = p; - ++numdnlines; - } - } - } - - add = GRSThttpGetCGI("add"); - - realfile = GRSThttpUrlEncode(file); - - dir_path_file = malloc(strlen(dir_path) + strlen(realfile) + 2); - strcpy(dir_path_file, dir_path); - strcat(dir_path_file, "/"); - strcat(dir_path_file, realfile); - - dir_path_tmpfile = malloc(strlen(dir_path) + 13); - strcpy(dir_path_tmpfile, dir_path); - strcat(dir_path_tmpfile, "/.tmp.XXXXXX"); - - if (((ofd = mkstemp(dir_path_tmpfile)) != -1) && - ((ofp = fdopen(ofd, "w")) != NULL)) - { - if (*add != '\0') - { - fputs(add, ofp); - fputc('\n', ofp); - } - - for (i=0; i < numdnlines; ++i) - { - fputs(dnlines[i], ofp); - fputc('\n', ofp); - } - - if ((fclose(ofp) == 0) && - ((stat(dir_path_file, &statbuf) != 0) || - (unlink(dir_path_file) == 0)) && - (rename(dir_path_tmpfile, dir_path_file) == 0)) - { - printf("Status: 302 Moved Temporarily\nContent-Length: 0\n" - "Location: %s%s?cmd=managedir\n\n", dir_uri, admin_file); - return; - } - } - - puts("Status: 500 Failed trying to write\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp,"Error writing %s%s\n", dir_uri, file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Error writing %s%s

\n", - dir_uri, file); - - GRSThttpPrintf(&bp, "

GridSite considers you are authorized " - "to write the file, but the write failed. This is " - "probably a web server or operating system level " - "misconfiguration. Consult the site administrator."); - - GRSThttpPrintf(&bp,"

" - "Return to " - "directory listing\n", dir_uri, admin_file); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); - - /* try to clean up */ - if (stat(dir_path_tmpfile, &statbuf) == 0) unlink(dir_path_tmpfile); -} - -void printfile(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - int fd; - char *dir_path_file; - struct stat statbuf; - - if (!GRSTgaclPermHasRead(perm)) GRSThttpError("403 Forbidden"); - - if (index(file, '/') != NULL) GRSThttpError("403 Forbidden"); - - dir_path_file = malloc(strlen(dir_path) + strlen(file) + 2); - - strcpy(dir_path_file, dir_path); - strcat(dir_path_file, "/"); - strcat(dir_path_file, file); - - fd = open(dir_path_file, O_RDONLY); - if (fd == -1) GRSThttpError("500 Internal server error"); - - if ((fstat(fd, &statbuf) != 0) || - !S_ISREG(statbuf.st_mode)) GRSThttpError("403 Forbidden"); - - printf("Status: 200 OK\nContent-Type: text/html\nContent-Length: %d\n\n", - statbuf.st_size); - - fflush(stdout); - - sendfile(1, fd, 0, statbuf.st_size); -} - -void filehistory(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - int fd, n, i, j, enclen, num = 0; - char *encodedfile, *p, *dndecoded, modified[99], *vfile, *q, - *encdn; - time_t file_time; - size_t file_size; - struct stat statbuf; - struct dirent **namelist; - struct tm file_tm; - GRSThttpBody bp; - - if (!GRSTgaclPermHasRead(perm)) GRSThttpError("403 Forbidden"); - - if (index(file, '/') != NULL) GRSThttpError("403 Forbidden"); - - puts("Status: 200 OK\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - GRSThttpPrintf(&bp, "History of %s%s\n", dir_uri, file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - GRSThttpPrintf(&bp, - "

History of %s%s

\n", - dir_uri, file, dir_uri, file); - - asprintf(&vfile, "%s/%s", dir_path, file); - if (stat(vfile, &statbuf) == 0) - { - localtime_r((const time_t *) &(statbuf.st_mtime), &file_tm); - strftime(modified, sizeof(modified), - "%a %e %b %Y %k:%M", &file_tm); - - GRSThttpPrintf(&bp, "

Last modified: %s\n", modified); - } - free(vfile); - - encodedfile = GRSThttpUrlEncode(file); - for (p=encodedfile; *p != '\0'; ++p) if (*p == '%') *p = '='; - enclen = strlen(encodedfile); - - n = scandir(dir_path, &namelist, 0, alphasort); - - if (n > 0) - { - for (i = n - 1; i >= 0; --i) - { - if ((strncmp(namelist[i]->d_name, GRST_HIST_PREFIX, - sizeof(GRST_HIST_PREFIX) - 1) == 0) && - ((namelist[i]->d_name)[sizeof(GRST_HIST_PREFIX) - 1] == ':') && - (strncmp(&((namelist[i]->d_name)[sizeof(GRST_HIST_PREFIX)]), - encodedfile, enclen) == 0) && - ((namelist[i]->d_name)[sizeof(GRST_HIST_PREFIX)+enclen] == ':')) - { - if (num == 0) GRSThttpPrintf(&bp, - "

\n" - "" - "\n"); - - ++num; - - p = index(namelist[i]->d_name, ':'); - p = index(&p[1], ':'); - sscanf(&p[1], "%X:", &file_time); - p = index(&p[1], ':'); /* skip over microseconds time */ - p = index(&p[1], ':'); - sscanf(&p[1], "%X:", &file_size); - p = index(&p[1], ':'); - - encdn = strdup(&p[1]); - q = index(encdn, ':'); - if (q != NULL) *q = '\0'; - - for (q=encdn; *q != '\0'; ++q) if (*q == '=') *q = '%'; - dndecoded = GRSThttpUrlDecode(encdn); - - localtime_r((const time_t *) &file_time, &file_tm); - strftime(modified, sizeof(modified), - "%a %e %b %Y %k:%M", &file_tm); - - GRSThttpPrintf(&bp, - "\n", - modified, file_size, dndecoded); - - free(dndecoded); - - asprintf(&vfile, "%s/%s", dir_path, namelist[i]->d_name); - if ((stat(vfile, &statbuf) == 0) && (statbuf.st_size > 0)) - { - GRSThttpPrintf(&bp, "\n", - dir_uri, admin_file, dir_uri, namelist[i]->d_name); - else GRSThttpPrintf(&bp, "%s%s\">View\n", - dir_uri, namelist[i]->d_name); - } - else GRSThttpPrintf(&bp, ""); - - free(vfile); - } - } - } - - if (num > 0) GRSThttpPrintf(&bp, "
DateSize afterChanged by
%s%d%sView
 
\n"); - else GRSThttpPrintf(&bp, "

No history for this file\n"); - - if (GRSTgaclPermHasList(perm)) - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - else adminfooter(&bp, dn, help_uri, dir_uri, NULL); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - GRSThttpWriteOut(&bp); -} - -void ziplist(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - char *shellcmd, *unzip, oneline[129]; - FILE *fp; - GRSThttpBody bp; - - if (!GRSTgaclPermHasRead(perm)) GRSThttpError("403 Forbidden"); - - if (index(file, '/') != NULL) GRSThttpError("403 Forbidden"); - - puts("Status: 200 OK\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - GRSThttpPrintf(&bp, "Contents of %s%s\n", dir_uri, file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - GRSThttpPrintf(&bp, - "

Contents of ZIP file %s%s

\n", - dir_uri, file, dir_uri, file); - - unzip = getenv("GRST_UNZIP"); - if (unzip == NULL) unzip = getenv("REDIRECT_GRST_UNZIP"); - - if (unzip != NULL) - { - GRSThttpPrintf(&bp, "
\n");
-      asprintf(&shellcmd, "cd %s ; %s -Z %s", dir_path, unzip, file);
-      fp = popen(shellcmd, "r");
-  
-      while (fgets(oneline, sizeof(oneline), fp) != NULL)           
-                          GRSThttpPrintf(&bp, "%s", oneline);         
-      pclose(fp);
-      GRSThttpPrintf(&bp, "
\n"); - - if (GRSTgaclPermHasWrite(perm)) - GRSThttpPrintf(&bp, - "

" - " in %s" - "" - "
" - "

(All files are placed in the same directory and files " - "beginning with "." are ignored.)

\n", - dir_uri, admin_file, dir_uri, file); - } - else GRSThttpPrintf(&bp, "

unzip path not defined!\n"); - - if (GRSTgaclPermHasList(perm)) - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - else adminfooter(&bp, dn, help_uri, dir_uri, NULL); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - GRSThttpWriteOut(&bp); -} - -void unzipfile(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - char *shellcmd, *unzip, oneline[129]; - FILE *fp; - GRSThttpBody bp; - - if (!GRSTgaclPermHasWrite(perm)) GRSThttpError("403 Forbidden"); - - if (index(file, '/') != NULL) GRSThttpError("403 Forbidden"); - - puts("Status: 200 OK\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - GRSThttpPrintf(&bp, "Unzipping %s%s\n", dir_uri, file); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - GRSThttpPrintf(&bp, - "

Unzipping %s%s

\n", - dir_uri, file, dir_uri, file); - - unzip = getenv("GRST_UNZIP"); - if (unzip == NULL) unzip = getenv("REDIRECT_GRST_UNZIP"); - - if (unzip != NULL) - { - GRSThttpPrintf(&bp, "
\n");
-      asprintf(&shellcmd, "cd %s ; %s -jo %s -x '.*'", dir_path, unzip, file);
-      fp = popen(shellcmd, "r");
-  
-      while (fgets(oneline, sizeof(oneline), fp) != NULL)           
-                          GRSThttpPrintf(&bp, "%s", oneline);         
-      pclose(fp);
-      GRSThttpPrintf(&bp, "
\n"); - - if (GRSTgaclPermHasList(perm)) - GRSThttpPrintf(&bp, "

" - "Back to " - "directory", dir_uri, admin_file); - } - else GRSThttpPrintf(&bp, "

unzip path not defined!\n"); - - if (GRSTgaclPermHasList(perm)) - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - else adminfooter(&bp, dn, help_uri, dir_uri, NULL); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - GRSThttpWriteOut(&bp); -} - -void editfileform(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - int fd, rawpagesize, i, c; - char *dir_path_file, *rawpage, *p; - FILE *fp = NULL; - struct stat statbuf; - GRSThttpBody bp; - - if (!GRSTgaclPermHasWrite(perm)) GRSThttpError("403 Forbidden"); - - if (index(file, '/') != NULL) GRSThttpError("403 Forbidden"); - - dir_path_file = malloc(strlen(dir_path) + strlen(file) + 2); - - strcpy(dir_path_file, dir_path); - strcat(dir_path_file, "/"); - strcat(dir_path_file, file); - - fd = open(dir_path_file, O_RDONLY); - if (fd != -1) - { - fp = fdopen(fd, "r"); - if (fp == NULL) GRSThttpError("500 File open failed!"); - - if ((fstat(fd, &statbuf) != 0) || - !S_ISREG(statbuf.st_mode)) GRSThttpError("500 Not a regular file!"); - } - - puts("Status: 200 OK\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp, "Edit file %s\n", file); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Edit file %s

\n", file); - - GRSThttpPrintf(&bp,"
\n",dir_uri,admin_file); - GRSThttpPrintf(&bp,"

\n"); - GRSThttpPrintf(&bp,"

File name: \n", file); - GRSThttpPrintf(&bp,"\n"); - GRSThttpPrintf(&bp,"

\n"); - GRSThttpPrintf(&bp, "

\n"); - GRSThttpPrintf(&bp, "

\n"); - - if (fp != NULL) fclose(fp); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - GRSThttpWriteOut(&bp); -} - -void editdnlistform(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *file, char *dir_uri, char *admin_file) -{ - int fd, i, c, numdn = 0; - char *dir_path_file, *rawpage, *p, *dnlistsuri, *server_name, *fulluri, - *realfile, oneline[513]; - FILE *fp = NULL; - struct stat statbuf; - GRSThttpBody bp; - - dnlistsuri = getenv("GRST_DN_LISTS_URI"); - if (dnlistsuri == NULL) dnlistsuri = getenv("REDIRECT_GRST_DN_LISTS_URI"); - - if (!GRSTgaclPermHasWrite(perm) || - (dnlistsuri == NULL) || - (strncmp(dnlistsuri, dir_uri, strlen(dnlistsuri)) != 0)) - GRSThttpError("403 Forbidden"); - - realfile = GRSThttpUrlEncode(file); - - dir_path_file = malloc(strlen(dir_path) + strlen(realfile) + 2); - - strcpy(dir_path_file, dir_path); - strcat(dir_path_file, "/"); - strcat(dir_path_file, realfile); - - fd = open(dir_path_file, O_RDONLY); - if (fd != -1) /* we dont mind open failing, but it must work if it doesnt */ - { - fp = fdopen(fd, "r"); - if (fp == NULL) GRSThttpError("500 File open failed!"); - - if ((fstat(fd, &statbuf) != 0) || - !S_ISREG(statbuf.st_mode)) GRSThttpError("500 Not a regular file!"); - } - - puts("Status: 200 OK\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp, "Edit DN List %s\n", file); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Edit DN List

\n"); - - GRSThttpPrintf(&bp,"
\n",dir_uri,admin_file); - GRSThttpPrintf(&bp,"

\n"); - GRSThttpPrintf(&bp,"

List URL: \n", file, strlen(file)); - GRSThttpPrintf(&bp,"\n"); - - if (fp != NULL) - { - GRSThttpPrintf(&bp, "

\n" - "\n"); - - while (fgets(oneline, sizeof(oneline), fp) != NULL) - { - ++numdn; - - p = rindex(oneline, '\n'); - if (p != NULL) *p = '\0'; - - GRSThttpPrintf(&bp, "" - "\n", numdn, oneline, oneline); - } - - GRSThttpPrintf(&bp,"
Keep?Name
%s
\n"); - } - - GRSThttpPrintf(&bp,"\n", numdn); - - GRSThttpPrintf(&bp, "

Add new DN: \n"); - - GRSThttpPrintf(&bp,"

\n"); - GRSThttpPrintf(&bp, "

\n"); - - if (fp != NULL) fclose(fp); - - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - GRSThttpWriteOut(&bp); -} - -void managedir(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *dir_uri, char *admin_file) -{ - int n, is_dnlists_dir = 0, enclen, numfiles, encprefixlen; - char *d_namepath, modified[99], *absaclpath, *editable, *p, *unzip, - *dnlistsuri, *d_name, *server_name, *fulluri, *encfulluri, - *encprefix, *dnlistsprefix; - GRSThttpBody bp; - struct tm mtime_tm; - struct stat statbuf; - struct dirent **namelist, *subdirfile_ent; - DIR *subDIR; - - if (((!GRSTgaclPermHasWrite(perm)) && - (!GRSTgaclPermHasList(perm))) || - (stat(dir_path, &statbuf) != 0) || !S_ISDIR(statbuf.st_mode)) - GRSThttpError("403 Forbidden"); - - editable = getenv("GRST_EDITABLE"); - if (editable == NULL) editable = getenv("REDIRECT_GRST_EDITABLE"); - - unzip = getenv("GRST_UNZIP"); - if (unzip == NULL) unzip = getenv("REDIRECT_GRST_UNZIP"); - - dnlistsuri = getenv("GRST_DN_LISTS_URI"); - if (dnlistsuri == NULL) dnlistsuri = getenv("REDIRECT_GRST_DN_LISTS_URI"); - - if (dnlistsuri && (strncmp(dnlistsuri, dir_uri, strlen(dnlistsuri)) == 0)) - { - is_dnlists_dir = 1; - server_name = getenv("SERVER_NAME"); - - asprintf(&fulluri, "https://%s%s", server_name, dir_uri); - encfulluri = GRSThttpUrlEncode(fulluri); - enclen = strlen(encfulluri); - - asprintf(&dnlistsprefix, "https://%s%s", server_name, dnlistsuri); - encprefix = GRSThttpUrlEncode(dnlistsprefix); - encprefixlen = strlen(encprefix); - } - - printf("Status: 200 OK\nContent-Type: text/html\n"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintf(&bp,"Manage directory %s\n", dir_uri); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpPrintf(&bp, "

Manage directory %s

\n\n", dir_uri); - - if (dir_uri[1] != '\0') - GRSThttpPrintf(&bp, - "\n", admin_file); - - if (GRSTgaclPermHasList(perm) || GRSTgaclPermHasAdmin(perm)) - { - absaclpath = malloc(strlen(dir_path) + sizeof(GRST_ACL_FILE) + 1); - strcpy(absaclpath, dir_path); - strcat(absaclpath, "/"); - strcat(absaclpath, GRST_ACL_FILE); - - if (stat(absaclpath, &statbuf) == 0) /* ACL exists in THIS directory */ - { - localtime_r(&(statbuf.st_mtime), &mtime_tm); - strftime(modified, sizeof(modified), - "", - &mtime_tm); - - if (!is_dnlists_dir) - { - GRSThttpPrintf(&bp, - "" - "%s\n", - GRST_ACL_FILE, - GRST_ACL_FILE, - statbuf.st_size, modified); - - GRSThttpPrintf(&bp, - "", - dir_uri, admin_file, GRST_ACL_FILE); - } - else GRSThttpPrintf(&bp, - "" - "%s\n", - GRST_ACL_FILE, - statbuf.st_size, modified); - - if (GRSTgaclPermHasAdmin(perm)) - GRSThttpPrintf(&bp, - "" - "", - dir_uri, admin_file, - dir_uri, admin_file, GRST_ACL_FILE); - else if (GRSTgaclPermHasRead(perm)) - GRSThttpPrintf(&bp, - "" - "", dir_uri, admin_file); - else GRSThttpPrintf(&bp, "\n"); - - GRSThttpPrintf(&bp, "\n"); - } - else if (GRSTgaclPermHasAdmin(perm)) - GRSThttpPrintf(&bp, "\n" - "\n" - "\n", - dir_uri, admin_file); - } - - if (GRSTgaclPermHasList(perm)) - { - n = scandir(dir_path, &namelist, 0, alphasort); - while (n--) - { - if (namelist[n]->d_name[0] != '.') - { - d_namepath = malloc(strlen(dir_path) + - strlen(namelist[n]->d_name) + 2); - strcpy(d_namepath, dir_path); - strcat(d_namepath, "/"); - strcat(d_namepath, namelist[n]->d_name); - stat(d_namepath, &statbuf); - - if (S_ISDIR(statbuf.st_mode)) - { - subDIR = opendir(d_namepath); - - if (subDIR == NULL) numfiles = 99; /* stop deletion */ - else - { - numfiles = 0; - while ((subdirfile_ent = readdir(subDIR)) != NULL) - if (subdirfile_ent->d_name[0] != '.') ++numfiles; - else if (strncmp(subdirfile_ent->d_name, - GRST_ACL_FILE, - sizeof(GRST_ACL_FILE)) == 0) ++numfiles; - - closedir(subDIR); - } - } - - free(d_namepath); - - localtime_r(&(statbuf.st_mtime), &mtime_tm); - strftime(modified, sizeof(modified), - "", - &mtime_tm); - - if (S_ISDIR(statbuf.st_mode)) - { - GRSThttpPrintf(&bp, - "" - "%s\n", - dir_uri, namelist[n]->d_name, admin_file, - namelist[n]->d_name, - statbuf.st_size, modified); - - if (numfiles == 0) - GRSThttpPrintf(&bp, - "\n", - dir_uri, admin_file, namelist[n]->d_name); - else GRSThttpPrintf(&bp, "\n"); - - GRSThttpPrintf(&bp, "\n"); - } - else if (is_dnlists_dir) - { - if ((strlen(namelist[n]->d_name) <= encprefixlen) || - (strncmp(namelist[n]->d_name, encprefix, - encprefixlen) != 0)) continue; - - d_name = GRSThttpUrlDecode(namelist[n]->d_name); - - GRSThttpPrintf(&bp, "" - "%s" - "", - d_name, d_name, - statbuf.st_size, modified); - - if (GRSTgaclPermHasWrite(perm)) - GRSThttpPrintf(&bp, "" - "" - "" - "" - "\n", - dir_uri, admin_file, d_name); - else GRSThttpPrintf(&bp, "\n"); - - if (GRSTgaclPermHasWrite(perm)) - GRSThttpPrintf(&bp, "" - "" - "" - "" - "\n", - dir_uri, admin_file, d_name); - else GRSThttpPrintf(&bp, "\n"); - - GRSThttpPrintf(&bp, ""); - } - else /* regular directory, not DN Lists */ - { - d_name = namelist[n]->d_name; - - GRSThttpPrintf(&bp, - "" - "%s", - dir_uri, d_name, - d_name, - statbuf.st_size, modified); - - GRSThttpPrintf(&bp, - "", - dir_uri, admin_file, d_name); - - p = rindex(namelist[n]->d_name, '.'); - - if ((unzip != NULL) && - (p != NULL) && - (strcasecmp(&p[1], "zip") == 0) && - GRSTgaclPermHasRead(perm)) - GRSThttpPrintf(&bp, - "\n", - dir_uri, admin_file, d_name); - else if ((p != NULL) && - (strstr(editable, &p[1]) != NULL) && - GRSTgaclPermHasWrite(perm)) - GRSThttpPrintf(&bp, - "\n", - dir_uri, admin_file, d_name); - else GRSThttpPrintf(&bp, ""); - - if (GRSTgaclPermHasWrite(perm)) - GRSThttpPrintf(&bp, - "\n", dir_uri, admin_file, d_name); - else - GRSThttpPrintf(&bp, "\n"); - - if (GRSTgaclPermHasWrite(perm)) - GRSThttpPrintf(&bp, - "\n", dir_uri, admin_file, d_name); - else - GRSThttpPrintf(&bp, ""); - } - } - - free(namelist[n]); - } - - free(namelist); - } - - if (GRSTgaclPermHasWrite(perm)) - { - if (is_dnlists_dir) - { - GRSThttpPrintf(&bp, "\n" - "" - "\n" - "\n", - dir_uri, admin_file, fulluri, strlen(fulluri)+8); - - GRSThttpPrintf(&bp, "\n" - "\n" - "\n", - dir_uri, admin_file); - } - else - { - GRSThttpPrintf(&bp, "\n" - "\n" - "" - "\n" - "\n" - "\n", - dir_uri, admin_file); - - GRSThttpPrintf(&bp, - "\n" - "\n" - "" - "" - "\n" - "" - "\n" - "\n", dir_uri, admin_file); - } - } - - GRSThttpPrintf(&bp, "
[Parent " - "directory]
%R%e %b %y
%s%ld" - "History
%s%ldEditDeleteView    
%R%e %b %y
" - "%s/%ld " - "Delete  
%s%ld 
 
  
%s%ld" - "History" - "List" - "Edit " - "Delete " - "Rename
 
New list name: " - "\n" - "
New directory: " - "\n" - "

New name:\n" - "

Upload file:New name: " - "
Local name:
\n"); - - if (!is_dnlists_dir) adminfooter(&bp, dn, help_uri, dir_uri, NULL); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - GRSThttpWriteOut(&bp); -} - diff --git a/org.gridsite.core/src/grst_admin_gacl.c b/org.gridsite.core/src/grst_admin_gacl.c deleted file mode 100644 index 2a40b28..0000000 --- a/org.gridsite.core/src/grst_admin_gacl.c +++ /dev/null @@ -1,968 +0,0 @@ -/* - Copyright (c) 2003, Shiv Kaushal, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/*-----------------------------------------------------------* -* This program is part of GridSite: http://www.gridsite.org/ * -*------------------------------------------------------------*/ - -#include -#include -#include -#include -#include -#include - -extern char *grst_perm_syms[]; -extern int grst_perm_vals[]; - -#include "grst_admin.h" - -// CGI GACL Editor interface functions -void show_acl(int admin, GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void new_entry_form(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void new_entry(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void del_entry(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void edit_entry_form(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void edit_entry(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void add_cred_form(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void add_cred(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void del_cred(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void del_entry_sure(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void del_cred_sure(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void admin_continue(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file, GRSThttpBody *bp); - -// Functions for producing HTML output -void StartHTML(GRSThttpBody *bp, char *dir_uri, char* dir_path); -void StartForm(GRSThttpBody *bp, char* dir_uri, char* dir_path, char* admin_file, int timestamp, char* target_function); -void EndForm(GRSThttpBody *bp); -void GRSTgaclCredTableStart(GRSThttpBody *bp); -void GRSTgaclCredTableAdd(GRSTgaclUser *user, GRSTgaclEntry *entry, GRSTgaclCred *cred, GRSTgaclNamevalue *namevalue, int cred_no, int entry_no, int admin, int timestamp, GRSThttpBody *bp, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); -void GRSTgaclCredTableEnd(GRSTgaclEntry* entry, int entry_no, int admin, int timestamp, GRSThttpBody *bp, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); - -// ACL Manipulation functions -int GACLentriesInAcl(GRSTgaclAcl *acl); -int GRSTgaclCredsInEntry(GRSTgaclEntry *entry); -void check_acl_save(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file, GRSTgaclUser* user, GRSTgaclAcl *acl, GRSThttpBody *bp); -void GACLeditGetPerms(GRSTgaclEntry *entry); -GRSTgaclEntry *GACLreturnEntry(GRSTgaclAcl *acl, int entry_no); -GRSTgaclCred *GACLreturnCred(GRSTgaclEntry *entry, int cred_no); - -void StringHTMLEncode (char* string, GRSThttpBody *bp); - -void revert_acl(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file); - -/*****************************************/ -/********** FUNCTIONS FOLLOW *************/ -/*****************************************/ - -void show_acl(int admin, GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Shows the contents of the ACL. Gives edit 'buttons' if (int admin) == 1 - GRSTgaclAcl *acl; - GRSTgaclEntry *entry; - GRSTgaclCred *cred; - GRSTgaclNamevalue *namevalue; - int entry_no, cred_no, allow, deny,timestamp; - GRSThttpBody bp; - char* AclFilename; - struct stat file_info; - int history_mode=0; - - if (admin==2){ - history_mode=1; - admin=0; - } - - /*double-check access permision*/ - if (!GRSTgaclPermHasAdmin(perm)) admin=0; - - StartHTML(&bp, dir_uri, dir_path); - - /* Load ACL from file and get timestamp*/ - if (history_mode==1) { - AclFilename=malloc(strlen(dir_path)+strlen(file)+2); - strcpy(AclFilename, dir_path); - strcat(AclFilename, "/"); - strcat(AclFilename, file); - } - else AclFilename=GRSTgaclFileFindAclname(dir_path); - - if (AclFilename==NULL){ - GRSThttpPrintf ( &bp,"The ACL was not found !!!
\n"); - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, &bp); - return; - } - - stat(GRSTgaclFileFindAclname(dir_path), &file_info); - timestamp=file_info.st_mtime; - acl = GRSTgaclAclLoadFile(AclFilename); - - if (acl==NULL){ - GRSThttpPrintf ( &bp,"The ACL was found but could not be loaded - it could be incorrectly formatted
\n"); - adminfooter(&bp, dn, help_uri, dir_uri, NULL); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - GRSThttpWriteOut(&bp); - return; - } - - if (admin) GRSThttpPrintf (&bp,"New Entry
\n", dir_uri, admin_file, dir_uri, timestamp ); - - // Start with the first entry in the list and work through - entry=acl->firstentry; - entry_no=1; - while (entry!=NULL){ - - GRSThttpPrintf (&bp,"
Entry %d:\n", entry_no); - if (admin){ - GRSThttpPrintf (&bp,"Edit Entry ", dir_uri, admin_file, entry_no, dir_uri, timestamp ); - GRSThttpPrintf (&bp,"Delete Entry ",dir_uri, admin_file, entry_no, dir_uri, timestamp ); - GRSThttpPrintf (&bp,"

\n"); - } - - GRSTgaclCredTableStart(&bp); - - // Start with the first credential in the entry and work through - cred=entry->firstcred; - cred_no=1; - while (cred!=NULL){ - namevalue=cred->firstname; - GRSTgaclCredTableAdd(user, entry, cred, namevalue, cred_no, entry_no, admin, timestamp, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - // Change to next credential - cred=cred->next; - cred_no++; - } - - GRSTgaclCredTableEnd (entry, entry_no, admin, timestamp, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - // Change to next entry - entry=entry->next; - entry_no++; - } - - if (!admin && GRSTgaclPermHasAdmin(perm) && !history_mode) //Print a link for admin mode, if not in admin mode but the user has admin permissions - GRSThttpPrintf (&bp,"Admin Mode", dir_uri, admin_file, dir_uri, timestamp ); - if (history_mode==1 && GRSTgaclDNlistHasUser(getenv("REDIRECT_GRST_ADMIN_LIST"), user)){ - StartForm(&bp, dir_uri, dir_path, admin_file, timestamp, "revert_acl"); -//GRSThttpPrintf (&bp,"Revert to this Version", dir_uri, admin_file, dir_uri, timestamp, file ); - GRSThttpPrintf (&bp, "\n", file); - // Revert Button - GRSThttpPrintf (&bp, "

\n\n"); - } - - adminfooter(&bp, dn, help_uri, dir_uri, NULL); - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); GRSThttpWriteOut(&bp); return; -} - - -void new_entry_form(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm,char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Presents the user with a form asking for details required to create a new entry - GRSThttpBody bp; - int timestamp=atol(GRSThttpGetCGI("timestamp")); - GRSTgaclCred* cred; - GRSTgaclEntry *entry; - GRSTgaclNamevalue* namevalue; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - StartHTML(&bp, dir_uri, dir_path); - StartForm(&bp, dir_uri, dir_path, admin_file, timestamp, "new_entry"); - GRSThttpPrintf (&bp, "NEW ENTRY IN ACL FOR %s

\n", dir_uri); - - GRSTgaclCredTableStart(&bp); - GRSTgaclCredTableAdd(user, entry,cred, namevalue, 0, 0, 0, timestamp, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - GRSTgaclCredTableEnd (entry, 0, 0, timestamp, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - - /*Submit and reset buttons - submit button sends the data in the form back to the script & new_entry() to be called*/ - EndForm(&bp); - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, &bp); - return; -} - -void new_entry(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Processes the information entered into the form from new_entry_form() and adds a new entry to the ACL - GRSTgaclAcl *acl; - GRSTgaclEntry *entry; - GRSTgaclCred *cred; - char *type, *value; - GRSThttpBody bp; - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - // Get new credential info and perform checks - type=GRSThttpGetCGI("type"); - value=GRSThttpGetCGI("cred0_value"); - - if (strcmp(type, "not_chosen")==0){ - GRSThttpError ("500 Invalid input - credential type not chosen"); - return; - } - - // Create the credential - cred=GRSTgaclCredNew(type); - if (strcmp(type, "person")==0) GRSTgaclCredAddValue(cred,"dn", value); - else if (strcmp(type, "dn-list")==0) GRSTgaclCredAddValue(cred, "url", value); - else if (strcmp(type, "voms")==0) GRSTgaclCredAddValue(cred, "fqan", value); - else if (strcmp(type, "dns")==0) GRSTgaclCredAddValue(cred, "hostname", value); - else if (strcmp(type, "any-user")==0) {} // namevalue not entered for any-user credential - else{ - GRSThttpError ("500 Invalid input - credential type not valid"); - return; - } - - // Create and empty entry, add the credential and get permissions - entry = GRSTgaclEntryNew(); - GRSTgaclEntryAddCred(entry, cred); - GACLeditGetPerms(entry); - - // Load the ACL, add the entry and save - acl = GRSTgaclAclLoadFile(GRSTgaclFileFindAclname(dir_path)); - GRSTgaclAclAddEntry(acl, entry); - check_acl_save(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, user, acl, &bp); - return; -} - -void del_entry(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Deletes the entry denoted by the GCI variable "entry_no"*/ - int entry_no; - GRSTgaclAcl *acl; - GRSTgaclEntry *previous, *entry; - GRSThttpBody bp; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - // Load the ACL - acl = GRSTgaclAclLoadFile(GRSTgaclFileFindAclname(dir_path)); - - // Get the number of the entry to be deleted and check okay to delete - entry_no=atol(GRSThttpGetCGI("entry_no")); - if(GACLentriesInAcl(acl)<=1){ - StartHTML(&bp, dir_uri, dir_path); - GRSThttpPrintf (&bp, "ERROR: Cannot delete all entries from the ACL
\n"); - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, &bp); - return; - } - - // Get pointer to entry and previous entry - entry = GACLreturnEntry(acl, entry_no); - if (entry_no!=1) previous = GACLreturnEntry(acl, entry_no-1); - - if(entry==NULL || entry_no<1 || entry_no>GACLentriesInAcl(acl) ){ - GRSThttpError ("500 Unable to read entry from ACL file"); - return; - } - - // Perform deletion from the list by changing pointers - if (entry_no==1) acl->firstentry=entry->next; - else if (entry_no==GACLentriesInAcl(acl)) previous->next=NULL; - else previous->next=entry->next; - - // Save ACL and exit - check_acl_save(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, user, acl, &bp); - - return; -} - - -void edit_entry_form(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Presents the user with an editable form containing details of entry denoted by CGI variable entry_no*/ - int entry_no, cred_no, i, admin=0, timestamp=atol(GRSThttpGetCGI("timestamp")); - GRSTgaclAcl *acl; - GRSTgaclEntry *entry; - GRSTgaclCred *cred; - GRSTgaclNamevalue *namevalue; - // struct _GACLnamevalue *namevalue; - GRSThttpBody bp; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - // Load ACL from file - acl = GRSTgaclAclLoadFile(GRSTgaclFileFindAclname(dir_path)); - - // Get pointer to the entry and check okay - entry_no=atol(GRSThttpGetCGI("entry_no")); - entry = GACLreturnEntry(acl, entry_no); - if(entry==NULL || entry_no<1 || entry_no>GACLentriesInAcl(acl) ){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - - StartHTML(&bp, dir_uri, dir_path); - GRSThttpPrintf (&bp, "EDITING ENTRY %d IN ACL FOR %s

\n", entry_no, dir_uri); - - // Start with first credential in the entry and display them in order*/ - cred=entry->firstcred; - cred_no=1; - StartForm(&bp, dir_uri, dir_path, admin_file, timestamp, "edit_entry"); - GRSThttpPrintf (&bp, "\n", entry_no); - - GRSTgaclCredTableStart(&bp); - - while (cred!=NULL){ - // Start with the first namevalue in the credential - namevalue=cred->firstname; - GRSTgaclCredTableAdd(user, entry, cred, namevalue, cred_no, entry_no, admin, timestamp, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - // Change to next credential - cred=cred->next; - cred_no++; - } - GRSTgaclCredTableEnd (entry, entry_no, admin, timestamp, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - EndForm(&bp); - - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, &bp); - return; -} - - -void edit_entry(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - //Processes the information entered into the form from edit_entry_form() and updates the entry corresponding to entry_no*/ - int entry_no, cred_no, i; - GRSTgaclAcl *acl; - GRSTgaclEntry *entry; - GRSTgaclCred *cred; - GRSTgaclNamevalue *namevalue; - char variable[30]; - GRSThttpBody bp; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - // Load the ACL - acl = GRSTgaclAclLoadFile(GRSTgaclFileFindAclname(dir_path)); - - // Get pointer to the entry and perform checks - entry_no=atol(GRSThttpGetCGI("entry_no")); - entry = GACLreturnEntry(acl, entry_no); - if(entry==NULL || entry_no<1 || entry_no>GACLentriesInAcl(acl) ){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - - // Start with the first credential and update each one - cred=entry->firstcred; - cred_no=1; - - while (cred!=NULL){ - if (strcmp(cred->type, "any-user")!=0){ - namevalue=cred->firstname; - sprintf(variable, "cred%d_value", cred_no); - namevalue->value=GRSThttpGetCGI(variable); - } - //Change to next credential*/ - cred=cred->next; - cred_no++; - } - - // Update permissions - GACLeditGetPerms(entry); - check_acl_save(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, user, acl, &bp); - return; -} - - -void add_cred_form(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Presents the user with a form asking for details required to create a new credential in the entry denoted by entry_no - GRSThttpBody bp; - int timestamp=atol(GRSThttpGetCGI("timestamp")), entry_no=atol(GRSThttpGetCGI("entry_no")); - GRSTgaclAcl *acl; - GRSTgaclEntry* entry; - GRSTgaclCred* cred; - GRSTgaclNamevalue* namevalue; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - acl = GRSTgaclAclLoadFile(GRSTgaclFileFindAclname(dir_path)); // Load the ACL - - //Get pointer to the entry and perform checks - entry = GACLreturnEntry(acl, entry_no); - if(entry==NULL || entry_no<1 || entry_no>GACLentriesInAcl(acl) ){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - - - if (strcmp(GRSThttpGetCGI("cmd"), "add_cred_form")==0){ //if not a new entry check to see if cred exists - cred=entry->firstcred; - while (cred!=NULL) { - if (strcmp (cred->type, "any-user")==0) { - StartHTML(&bp, dir_uri, dir_path); - GRSThttpPrintf (&bp, "ERROR: AND-ing \"any-user\" credential with other credential does not make sense
\n"); - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, &bp); - return; - } - cred=cred->next; - } - } - - StartHTML(&bp, dir_uri, dir_path); - GRSThttpPrintf (&bp, " NEW CREDENTIAL IN ENTRY %d OF ACL FOR %s

\n", entry_no, dir_uri); - StartForm(&bp, dir_uri, dir_path, admin_file, timestamp, "add_cred"); - - GRSThttpPrintf (&bp, " \n", entry_no); - - GRSTgaclCredTableStart(&bp); - GRSTgaclCredTableAdd(user, entry, cred, namevalue, 0, 0, 0, timestamp, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - GRSTgaclCredTableEnd (entry, 0, 0, timestamp, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - - EndForm(&bp); - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, &bp); - return; -} - - -void add_cred(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Processes the information entered into the form [add_cred_form()]and adds a new credential to the entry corresponding to entry_no - int entry_no; - GRSTgaclAcl *acl; - GRSTgaclEntry *entry; - GRSTgaclCred *cred; - GRSThttpBody bp; - char *type, *value; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - acl = GRSTgaclAclLoadFile(GRSTgaclFileFindAclname(dir_path));// Load the ACL - - // Get pointer to the entry and perform checks - entry_no=atol(GRSThttpGetCGI("entry_no")); - entry = GACLreturnEntry(acl, entry_no); - if(entry==NULL || entry_no<1 || entry_no>GACLentriesInAcl(acl)){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - - // Create new credential and add it to entry - type=GRSThttpGetCGI("type"); - value=GRSThttpGetCGI("cred0_value"); - cred=GRSTgaclCredNew(type); - if (strcmp(type, "person") ==0) GRSTgaclCredAddValue(cred,"dn", value); - else if (strcmp(type, "dn-list") ==0) GRSTgaclCredAddValue(cred, "url", value); - else if (strcmp(type, "voms") ==0) GRSTgaclCredAddValue(cred, "fqan", value); - else if (strcmp(type, "dns") ==0) GRSTgaclCredAddValue(cred, "hostname", value); - else if (strcmp(type, "any-user")==0) {}// namevalue not entered for any-user credential - else{ - GRSThttpError ("500 Credential type not valid"); - return; - } - GRSTgaclEntryAddCred(entry, cred); - - check_acl_save(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, user, acl, &bp); - return; -} - - -void del_cred(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Deletes the credential denoted by the GCI variable "cred_no", in the entry denoted by "entry_no" - int entry_no, cred_no; - GRSTgaclAcl *acl; - GRSTgaclEntry *entry; - GRSTgaclCred *previous, *cred; - GRSThttpBody bp; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - acl = GRSTgaclAclLoadFile(GRSTgaclFileFindAclname(dir_path)); - - // Get pointer to the entry and perform checks - entry_no=atol(GRSThttpGetCGI("entry_no")); - entry = GACLreturnEntry(acl, entry_no); - if(entry==NULL || entry_no<1 || entry_no>GACLentriesInAcl(acl) ){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - // Get pointer the the credential and perform checks - cred_no=atol(GRSThttpGetCGI("cred_no")); - cred=GACLreturnCred(entry, cred_no); - if(entry==NULL || entry_no<1 || cred_no>GRSTgaclCredsInEntry(entry)){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - // Get pointer to previous credential - if needed - if (cred_no!=1) previous = GACLreturnCred(entry, cred_no-1); - - // Perform deletion from the list by changing pointers - if (cred_no==1) entry->firstcred=cred->next; - else if (cred_no==GRSTgaclCredsInEntry(entry)) previous->next=NULL; - else previous->next=cred->next; - - check_acl_save(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, user, acl, &bp); - return; -} - -void admin_continue(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file, GRSThttpBody *bp){ - // Single line printed out to forward users back to show_acl in admin mode - // Should ALWAYS called from another function so no HTML header required - // Should ALWAYS be the end of a page - GRSThttpPrintf (bp, "\n
Click Here to return to the editor", dir_uri,admin_file,dir_uri, time(NULL)); - adminfooter(bp, dn, help_uri, dir_uri, NULL); - GRSThttpPrintHeaderFooter(bp, dir_path, GRST_FOOTFILE); - GRSThttpWriteOut(bp); - return; -} - - -void del_entry_sure(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Prints out entry denoted by entry_no and asks if the user really wants to delete it - GRSTgaclAcl *acl; - GRSTgaclEntry *entry; - GRSTgaclCred *cred; - GRSTgaclNamevalue *namevalue; - int entry_no, cred_no, allow, deny, i, timestamp; - GRSThttpBody bp; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - acl = GRSTgaclAclLoadFile(GRSTgaclFileFindAclname(dir_path));// Load ACL from file - - if (acl==NULL){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - - // Get pointer to the entry and check okay - entry_no=atol(GRSThttpGetCGI("entry_no")); - entry = GACLreturnEntry(acl, entry_no); - if(entry==NULL || entry_no<1 || entry_no>GACLentriesInAcl(acl) ){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - - StartHTML(&bp, dir_uri, dir_path); - GRSThttpPrintf (&bp, "

Do you really want to delete the following entry?



\n"); - GRSThttpPrintf (&bp,"
Entry %d:
\n", entry_no); - - // Print the entry out - // Start with the first credential in the entry and work through - cred=entry->firstcred; - cred_no=1; - - GRSTgaclCredTableStart(&bp); - while (cred!=NULL){ - // Start with the first namevalue in the credential - namevalue=cred->firstname; - GRSTgaclCredTableAdd(user, entry, cred, namevalue, cred_no, entry_no, 0, 0, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - // Change to next credential - cred=cred->next; - cred_no++; - } - - GRSTgaclCredTableEnd (entry, entry_no, 0, 0, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - - StartForm(&bp, dir_uri, dir_path, admin_file, atol(GRSThttpGetCGI("timestamp")), "del_entry"); - GRSThttpPrintf (&bp, "\n", entry_no); - GRSThttpPrintf (&bp, "

\n\n"); - - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, &bp); - return; -} - -void del_cred_sure(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Prints out credential denoted by entry_no/cred_no and asks if the user really wants to delete it - GRSTgaclAcl *acl; - GRSTgaclEntry *entry; - GRSTgaclCred *cred; - GRSTgaclNamevalue *namevalue; - int entry_no, cred_no, allow, deny, timestamp, i; - GRSThttpBody bp; - - if (!GRSTgaclPermHasAdmin(perm)) GRSThttpError ("403 Forbidden"); - - acl = GRSTgaclAclLoadFile(GRSTgaclFileFindAclname(dir_path));// Load ACL from file - - if (acl==NULL){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - - // Get pointer to the entry and check okay - entry_no=atol(GRSThttpGetCGI("entry_no")); - entry = GACLreturnEntry(acl, entry_no); - if(entry==NULL || entry_no<1 || entry_no>GACLentriesInAcl(acl) ){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - - // Get pointer to the credential and check okay - cred_no=atol(GRSThttpGetCGI("cred_no")); - cred=GACLreturnCred(entry, cred_no); - if(entry==NULL || entry_no<1 || cred_no>GRSTgaclCredsInEntry(entry)){ - GRSThttpError ("500 Unable to read from ACL file"); - return; - } - - if(GRSTgaclCredsInEntry(entry)<=1){ - del_entry_sure(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - return; - } - - StartHTML(&bp, dir_uri, dir_path); - GRSThttpPrintf (&bp, "

Do you really want to delete the following credential from entry %d?



", entry_no); - - // Print the credential out - GRSTgaclCredTableStart(&bp); - GRSTgaclCredTableAdd(user, entry, cred, cred->firstname, cred_no, entry_no, 0, 0, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - GRSTgaclCredTableEnd (entry, entry_no, 0, 0, &bp, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - GRSThttpPrintf (&bp,"
\n"); - - // Yes Button - StartForm(&bp, dir_uri, dir_path, admin_file, atol(GRSThttpGetCGI("timestamp")), "del_cred"); - GRSThttpPrintf (&bp, "\n", entry_no); - GRSThttpPrintf (&bp, "\n", cred_no); - GRSThttpPrintf (&bp, "

\n\n"); - - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, &bp); - return; -} - - -int GACLentriesInAcl(GRSTgaclAcl *acl){ - // Returns the number of entries in acl - GRSTgaclEntry *entry; - int number; - - entry=acl->firstentry; - number=0; - - while (entry!=NULL) - { - number++; - entry=entry->next; - } - - return number; -} - -int GRSTgaclCredsInEntry(GRSTgaclEntry *entry){ - // Returns the number of credentials in entry - int number; - GRSTgaclCred *cred; - - cred=entry->firstcred; - number=0; - - while (cred!=NULL) - { - number++; - cred=cred->next; - } - - return number; -} - - -void GACLeditGetPerms(GRSTgaclEntry *entry){ - // Updates the permissions entry using permissions from a form produced using GRSTgaclCredTableEnd - int i; - char buf[30]; - - - for (i=0; grst_perm_syms[i]!=NULL; i++) /* Print the list of allowed permissions*/ - { - sprintf (buf, "allow_%s", grst_perm_syms[i]); // Update allowed - if (strcmp (GRSThttpGetCGI(buf), "ON") == 0 ) GRSTgaclEntryAllowPerm(entry, grst_perm_vals[i]); else GRSTgaclEntryUnallowPerm(entry, grst_perm_vals[i]); - - sprintf (buf, "deny_%s", grst_perm_syms[i]); // Update denied - if (strcmp (GRSThttpGetCGI(buf), "ON") == 0 ) GRSTgaclEntryDenyPerm(entry, grst_perm_vals[i]); else GRSTgaclEntryUndenyPerm(entry, grst_perm_vals[i]); - - } - - return; -} - -GRSTgaclEntry *GACLreturnEntry(GRSTgaclAcl *acl, int entry_no){ - // Returns a pointer to entry in ACL denoted by entry_no, returns NULL if not found - int number; - GRSTgaclEntry *entry; - - if (acl==NULL) return NULL; - - entry=acl->firstentry; - number=1; - - while (entry!=NULL) - { - if (number==entry_no) return entry; - number++; - entry=entry->next; - } - - return NULL; -} - - -GRSTgaclCred *GACLreturnCred(GRSTgaclEntry *entry, int cred_no){ - // Returns a pointer to credential denoted by cred_no in entry, returns NULL if not found - int number; - GRSTgaclCred *cred; - - if (entry==NULL) return NULL; - - cred=entry->firstcred; - number=1; - - while (cred!=NULL) - { - if (number==cred_no) return cred; - number++; - cred=cred->next; - } - - return NULL; -} -void StartHTML(GRSThttpBody *bp, char *dir_uri, char* dir_path){ - //Start HTML output and insert page title - printf("Status: 200 OK\nContent-Type: text/html\n"); - GRSThttpBodyInit(bp); - GRSThttpPrintf(bp, "Access Control List for %s\n", dir_uri); - GRSThttpPrintHeaderFooter(bp, dir_path, GRST_HEADFILE); - return; -} -void StartForm(GRSThttpBody *bp, char* dir_uri, char* dir_path, char* admin_file, int timestamp, char* target_function){ - // Starts an HTML form with gridsite admin as the target and target_function as the value of cmd. - // Also inputs the dir_uri and the timestamp - GRSThttpPrintf (bp, "
\n", dir_uri, admin_file, dir_uri); - GRSThttpPrintf (bp, " \n", target_function); - GRSThttpPrintf (bp, " \n", timestamp); - return; -} - -void EndForm(GRSThttpBody *bp){ - GRSThttpPrintf (bp, "

\n"); - GRSThttpPrintf (bp, "
\n"); - return; -} - -void GRSTgaclCredTableStart(GRSThttpBody *bp){ - //Starts an HTML table of credentials by setting the column widths and inputting the headings - GRSThttpPrintf (bp,""); - GRSThttpPrintf (bp,""); - return; -} - -void GRSTgaclCredTableAdd(GRSTgaclUser *user, GRSTgaclEntry *entry, GRSTgaclCred *cred, GRSTgaclNamevalue *namevalue, int cred_no, int entry_no, int admin, int timestamp, GRSThttpBody *bp, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Adds the credential "cred" to a table started byGRSTgaclCredTableStart allowing the user to edit if appropriate - char* cmd = GRSThttpGetCGI("cmd"); - int edit_values=0, new_cred=0, allow_new_person=1; - int site_admin=GRSTgaclDNlistHasUser(getenv("REDIRECT_GRST_ADMIN_LIST"), user); - - if (strcmp(cmd, "new_entry_form")==0 || strcmp(cmd, "add_cred_form")==0) new_cred=1; - if (new_cred || strcmp(cmd, "edit_entry_form")==0) edit_values=1; - - if (new_cred) { /*Print out type and descriptor*/ - if (strcmp(cmd, "add_cred_form")==0){ /*if not a new entry check to see if cred exists.*/ - cred=entry->firstcred; - while (cred!=NULL) {if (strcmp (cred->type, "person")==0) allow_new_person=0; cred=cred->next;} - } - //create dummy credential for the user to edit - cred=GRSTgaclCredNew("new"); - GRSTgaclCredAddValue(cred, "", ""); - namevalue=cred->firstname; - //Drop down list of types - GRSThttpPrintf(bp,""); - GRSThttpPrintf(bp,""); - } - - else { //Print out type and descriptor for existing cred - - GRSThttpPrintf(bp,""); -} - -void GRSTgaclCredTableEnd(GRSTgaclEntry* entry, int entry_no, int admin, int timestamp, GRSThttpBody *bp, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - // Finishes off a table of credentials by inputting "Add Credential" link and a list of premissions in the final row - int i, blank_perms, edit_perms, show_perms; - char* cmd = GRSThttpGetCGI("cmd"); - - if (strcmp(cmd, "add_cred_form")==0 ||strcmp(cmd, "del_cred_sure")==0) show_perms=0; else show_perms=1; - if (strcmp(cmd, "edit_entry_form")==0 || strcmp(cmd, "new_entry_form")==0) edit_perms=1; else edit_perms=0; - if (strcmp(cmd, "new_entry_form")==0) blank_perms=1; else blank_perms=0; - - // If showing the last row is not required then exit - if (show_perms==0){GRSThttpPrintf (bp,"
Credential No.TypeValue
New"); - GRSThttpPrintf (bp, "
%d", cred_no); - if (admin) GRSThttpPrintf (bp,"(Delete)", dir_uri,admin_file,dir_uri, entry_no, cred_no, timestamp); - GRSThttpPrintf(bp, "%s ", cred->type); - } - - if (strcmp(cred->type, "any-user")==0) GRSThttpPrintf (bp, " "); /* Do not print out namevalue for any-user credential*/ - else{ - if (edit_values){ // Place namevalue in an editable box if appropriate - GRSThttpPrintf (bp, "value, bp); - GRSThttpPrintf (bp, "\">"); - } - else if (strcmp(cred->type, "dn-list")==0){ - GRSThttpPrintf(bp, "value, bp); - GRSThttpPrintf(bp, " \">"); - StringHTMLEncode(namevalue->value, bp); - GRSThttpPrintf(bp, ""); - } - else { GRSThttpPrintf(bp, " "); StringHTMLEncode(namevalue->value, bp);} - - } - //Print out warning symbol if cred being printed relates to current user - but NOT for users in site admin list - if (GRSTgaclUserHasCred(user, cred) && !site_admin) GRSThttpPrintf(bp, " <--"); - GRSThttpPrintf(bp, "

\n"); return;} - - GRSThttpPrintf (bp,""); - - if (admin) GRSThttpPrintf (bp,"Add Credential", dir_uri,admin_file,dir_uri, entry_no, timestamp); - - GRSThttpPrintf (bp, "\n "); - - if (blank_perms) entry->allowed=entry->denied=GRST_PERM_NONE; - - // Show Permissions - will produce a list or a list of check boxes depending on whether the permissions are to be edited or not - GRSThttpPrintf (bp, "Allowed: "); - for (i=0; grst_perm_syms[i]!=NULL; i++) /* Print the list of allowed permissions*/ - { - if ( entry->allowed & grst_perm_vals[i]){ - if (edit_perms) GRSThttpPrintf (bp, "%s   \n", grst_perm_syms[i],grst_perm_syms[i]); - else GRSThttpPrintf(bp,"%s ", grst_perm_syms[i]); if (strcmp(grst_perm_syms[i], "none")==0) break; - } - else if (strcmp(grst_perm_syms[i], "none")!=0 && edit_perms) GRSThttpPrintf (bp, "%s   \n", grst_perm_syms[i],grst_perm_syms[i]); - } - - if (edit_perms) GRSThttpPrintf (bp, "

"); - GRSThttpPrintf (bp, "Denied: "); - for (i=0; grst_perm_syms[i]!=NULL; i++) /* Print the list of denied permissions*/ - { - if ( entry->denied & grst_perm_vals[i]) - { - if (edit_perms) GRSThttpPrintf (bp, "%s   \n", grst_perm_syms[i],grst_perm_syms[i]); - else GRSThttpPrintf(bp,"%s ", grst_perm_syms[i]); - if (strcmp(grst_perm_syms[i], "none")==0) break; - } - else if (strcmp(grst_perm_syms[i], "none")!=0 && edit_perms) GRSThttpPrintf (bp, "%s   \n", grst_perm_syms[i],grst_perm_syms[i]); - } - - GRSThttpPrintf (bp, ""); - GRSThttpPrintf (bp,"
\n"); - GRSThttpPrintf (bp,"\n"); -} - -void check_acl_save(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file, GRSTgaclUser* user, GRSTgaclAcl *acl, GRSThttpBody *bp){ - // Checks if the acl for the current directory has been changed, check the current user's permissions. - // If all is okay the ACl is saved -> returns 1 else returns 0 - struct stat file_info; - GRSTgaclPerm new_perm; - char *vfile, *dir_path_vfile, *dir_path_file; - FILE *fp; - - - /*Check ACL has not been modified*/ - stat(GRSTgaclFileFindAclname(dir_path), &file_info); - if (atol(GRSThttpGetCGI("timestamp"))!=file_info.st_mtime){ - StartHTML(bp, dir_uri, dir_path); - GRSThttpPrintf (bp, "ERROR: CANNOT SAVE CHANGES

The ACL has been modified since it was last viewed\n

"); - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, bp); - return; - } - - // check users permissions in the new ACL - - if (!GRSTgaclDNlistHasUser(getenv("REDIRECT_GRST_ADMIN_LIST"), user)) - { - new_perm = GRSTgaclAclTestUser(acl, user); - if (new_perm != perm){ - StartHTML(bp, dir_uri, dir_path); - if (!GRSTgaclPermHasAdmin(new_perm)){//Check that user still has Admin permissions - if not then exit without saving the new ACL - GRSThttpPrintf (bp, "ERROR: CANNOT SAVE CHANGES\n\n

You cannot deny yourself admin access from within the editor\n"); - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, bp); - return; - } - //Functions to inform of other permission changes come next - GRSThttpPrintf (bp, "WARNING: OPERATION CHANGED YOUR PERMISSIONS!\n\n

You still have Admin permissions

\n"); - admin_continue(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, bp); - return; - } - } - // ACL not modified, notified of permission changes - can now save - - dir_path_file=GRSTgaclFileFindAclname(dir_path); - vfile=makevfilename(".gacl", file_info.st_size, dn); // Make temporary file name - dir_path_vfile = malloc(strlen(dir_path) + strlen(vfile) + 2); - strcpy(dir_path_vfile, dir_path); - strcat(dir_path_vfile, "/"); - strcat(dir_path_vfile, vfile); - - GRSTgaclAclSave(acl, dir_path_vfile); // save the new ACL to the temporary file - unlink(dir_path_file); - if (link (dir_path_vfile,dir_path_file)!=0) GRSThttpError("403 Forbidden"); - - printf ("Status: 302 Moved Temporarily\n Content Length: 0\nLocation: %s%s?cmd=admin_acl\n\n", dir_uri, admin_file); - return; -} - -void StringHTMLEncode (char* string, GRSThttpBody *bp){ - - char* current_char; - char* tmp; - int n; - tmp=malloc(2); - - *(tmp+1)='\0'; - current_char=string; - while(*current_char != '\0'){ - - if (*current_char == '<') GRSThttpPrintf (bp,"<"); - else if (*current_char == '>') GRSThttpPrintf (bp,">"); - else if (*current_char == '&') GRSThttpPrintf (bp,"&"); - else if (*current_char == '\'') GRSThttpPrintf (bp,"'"); - else if (*current_char == '"') GRSThttpPrintf (bp,"""); - else{ - *tmp=*current_char; - GRSThttpPrintf(bp, "%s", tmp); - - } - current_char++; - } - return; -} - -void revert_acl(GRSTgaclUser *user, char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, char *file, char *dir_uri, char *admin_file){ - char *AclFilename; - GRSTgaclAcl *acl; - GRSThttpBody bp; - // Load the old ACL, add the entry and save - AclFilename=malloc(strlen(dir_path)+strlen(file)+2); - strcpy(AclFilename, dir_path); - strcat(AclFilename, "/"); - strcat(AclFilename, file); - - acl = GRSTgaclAclLoadFile(AclFilename); - check_acl_save(dn, perm, help_uri, dir_path, file, dir_uri, admin_file, user, acl, &bp); - return; -} diff --git a/org.gridsite.core/src/grst_admin_main.c b/org.gridsite.core/src/grst_admin_main.c deleted file mode 100644 index d884bf5..0000000 --- a/org.gridsite.core/src/grst_admin_main.c +++ /dev/null @@ -1,365 +0,0 @@ -/* - Andrew McNab and Shiv Kaushal, University of Manchester. - Copyright (c) 2002-3. All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/*------------------------------------------------------------------* - * This program is part of GridSite: http://www.gridsite.org/ * - *------------------------------------------------------------------*/ - -#ifndef VERSION -#define VERSION "x.x.x" -#endif - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -// when porting: remember that sendfile() is very OS-specific! -#include - -#include - -#include "grst_admin.h" - -/* - - GridSite human/interactive management interface. This should produce - a CGI executable, usually ./sbin/real-gridsite-admin.cgi, which is - called from HTML forms either by GET or POST methods or both (ie input - present in both QUERY_STRING and the stdin of the CGI process.) - - The CGI name/value pairs used are: - - cmd = edit, managedir, print, history - file = short name of file, without path - - If real-gridsite-admin.cgi is run by an internal redirection inside - mod_gridsite (as should ALWAYS be the case) then the environment - variable REDIRECT_GRST_DIR_PATH will be set to the full path of - the directory holding the file in question. This respects any complex - URI -> file path mapping done by Apache. - -*/ - -void GRSThttpError(char *status) -{ - printf("Status: %s\n", status); - printf("Server-CGI: GridSite Admin %s\n", VERSION); - printf("Content-Length: %d\n", 2 * strlen(status) + 58); - puts("Content-Type: text/html\n"); - - printf("%s\n", status); - printf("

%s

\n", status); - - exit(0); -} - -void adminfooter(GRSThttpBody *bp, char *dn, char *help_uri, char *dir_uri, - char *admin_file) -{ - GRSThttpPrintf(bp, "

\n"); - - if (dn != NULL) GRSThttpPrintf(bp, "


You are %s
\n", dn); - else GRSThttpPrintf(bp, "
\n"); - - if (admin_file != NULL) - GRSThttpPrintf(bp, "" - "Manage directory .\n", - dir_uri, admin_file); - else GRSThttpPrintf(bp, "" - "Back to directory .\n", dir_uri); - - if (help_uri != NULL) - GRSThttpPrintf(bp, "Website Help .\n", help_uri); - - if ((getenv("GRST_NO_LINK") == NULL) && - (getenv("REDIRECT_GRST_NO_LINK") == NULL)) - GRSThttpPrintf(bp, "Built with " - "GridSite %s\n", - VERSION); - - GRSThttpPrintf(bp, "
\n"); -} - -int GRSTstrCmpShort(char *long_s, char *short_s) -{ - while (*short_s != '\0') - { - if (*long_s > *short_s) return +1; - if (*long_s < *short_s) return -1; - - ++long_s; - ++short_s; - } - - return 0; -} - -char *makevfilename(char *publicname, size_t size, char *dn) -{ - int i; - char *ext, *vfilename, *encpublicname, *encdn, *p; - struct timeval tv_now; - - gettimeofday(&tv_now, NULL); - - ext = rindex(publicname, '.'); - if (ext == NULL) ext = ""; - - encpublicname = GRSThttpUrlEncode(publicname); - for (p=encpublicname; *p != '\0'; ++p) if (*p == '%') *p = '='; - - encdn = GRSThttpUrlEncode(dn); - for (p=encdn; *p != '\0'; ++p) if (*p == '%') *p = '='; - - /* we used zero-padding for times so - alphanumeric sorting will sort chronologically too */ - - asprintf(&vfilename, "%s:%s:%08X:%05X:%X:%s:%s", GRST_HIST_PREFIX, - encpublicname, tv_now.tv_sec, tv_now.tv_usec, size, encdn, ext); - - return vfilename; -} - -void justheader(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *dir_uri, char *admin_file) -{ - GRSThttpBody bp; - - puts("Status: 200 OK\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_HEADFILE); - - GRSThttpWriteOut(&bp); -} - -void justfooter(char *dn, GRSTgaclPerm perm, char *help_uri, char *dir_path, - char *dir_uri, char *admin_file) -{ - GRSThttpBody bp; - - puts("Status: 200 OK\nContent-Type: text/html"); - - GRSThttpBodyInit(&bp); - - if (GRSTgaclPermHasList(perm) || GRSTgaclPermHasWrite(perm) - || GRSTgaclPermHasAdmin(perm)) - adminfooter(&bp, dn, help_uri, dir_uri, admin_file); - - GRSThttpPrintHeaderFooter(&bp, dir_path, GRST_FOOTFILE); - - GRSThttpWriteOut(&bp); -} - -int main() -{ - int gsiproxylimit_i = 1; - char *cmd, *dir_uri, *file, *dir_path, *admin_file, *dn = NULL, - *help_uri, *p, *content_type, *request_uri, *button, - *grst_cred_0, *gsiproxylimit, *dn_lists; - GRSTgaclCred *cred; - GRSTgaclUser *user = NULL; - GRSTgaclAcl *acl; - GRSTgaclPerm perm = GRST_PERM_NONE; - - help_uri = getenv("REDIRECT_GRST_HELP_URI"); /* can be NULL */ - admin_file = getenv("REDIRECT_GRST_ADMIN_FILE"); - dir_path = getenv("REDIRECT_GRST_DIR_PATH"); - request_uri = getenv("REQUEST_URI"); - - if ((dir_path == NULL) || (admin_file == NULL) || (request_uri == NULL)) - { - puts("Status: 500 Internal Server Error\nContent-type: text/plain\n\n" - "REDIRECT_GRST_DIR_PATH or REDIRECT_GRST_ADMIN_FILE " - "or REQUEST_URI missing"); - return; - } - - GRSTgaclInit(); - - grst_cred_0 = getenv("GRST_CRED_0"); - - if ((grst_cred_0 != NULL) && (cred = GRSTx509CompactToCred(grst_cred_0))) - { - gsiproxylimit = getenv("REDIRECT_GRST_GSIPROXY_LIMIT"); - if (gsiproxylimit != NULL) sscanf(gsiproxylimit, "%d", &gsiproxylimit_i); - - if (GRSTgaclCredGetDelegation(cred) <= gsiproxylimit_i) - { - user = GRSTgaclUserNew(cred); - - if ((p = index(grst_cred_0, ' ')) && - (p = index(++p, ' ')) && - (p = index(++p, ' ')) && - (p = index(++p, ' '))) dn = &p[1]; - } - } - else if ((dn = getenv("SSL_CLIENT_S_DN")) != NULL) - { - cred = GRSTgaclCredNew("person"); - GRSTgaclCredAddValue(cred, "dn", dn); - user = GRSTgaclUserNew(cred); - } - - dn_lists = getenv("REDIRECT_GRST_DN_LISTS"); - if (dn_lists == NULL) dn_lists = getenv("GRST_DN_LISTS"); - if (dn_lists != NULL) GRSTgaclUserSetDNlists(user, dn_lists); - - if (GRSTgaclDNlistHasUser(getenv("REDIRECT_GRST_ADMIN_LIST"), - user)) perm = GRST_PERM_ALL; - else - { - p = getenv("REMOTE_HOST"); - if (p != NULL) - { - cred = GRSTgaclCredNew("dns"); - GRSTgaclCredAddValue(cred, "hostname", p); - - if (user == NULL) user = GRSTgaclUserNew(cred); - else GRSTgaclUserAddCred(user, cred); - } - - acl = GRSTgaclAclLoadforFile(dir_path); - if (acl != NULL) perm = GRSTgaclAclTestUser(acl, user); - } - - /* we're relying on being a CGI with all this un-free()ed strdup()ing */ - - dir_uri = strdup(request_uri); - p = rindex(dir_uri, '?'); - if (p != NULL) *p = '\0'; - p = rindex(dir_uri, '/'); - if (p != NULL) p[1] = '\0'; - - content_type = getenv("CONTENT_TYPE"); - - if ((content_type != NULL) && - (GRSTstrCmpShort(content_type, "multipart/form-data; boundary=") == 0)) - { - uploadfile(dn, perm, help_uri, dir_path, dir_uri, admin_file); - return 0; - } - - cmd = GRSThttpGetCGI("cmd"); - file = GRSThttpGetCGI("file"); - button = GRSThttpGetCGI("button"); - - /* file and directory functions in grst_admin_file.c */ - - if (strcmp(cmd, "header") == 0) - justheader(dn, perm, help_uri, dir_path, dir_uri, admin_file); - else if (strcmp(cmd, "footer") == 0) - justfooter(dn, perm, help_uri, dir_path, dir_uri, admin_file); - else if (strcmp(cmd, "managedir") == 0) - managedir(dn, perm, help_uri, dir_path, dir_uri, admin_file); - else if (strcmp(cmd, "print") == 0) - printfile(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "history") == 0) - filehistory(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "editdnlist") == 0) - editdnlistform(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "edit") == 0) - { - if ((strcasecmp(button, "new directory") == 0) || - (strcasecmp(button, "Create") == 0)) - newdirectory(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else - editfileform(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - } - else if (strcmp(cmd, "editaction") == 0) - editfileaction(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "editdnlistaction") == 0) - editdnlistaction(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "delete") == 0) - deletefileform(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "deleteaction") == 0) - deletefileaction(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "rename") == 0) - renameform(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "renameaction") == 0) - renameaction(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "ziplist") == 0) - ziplist(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "unzipfile") == 0) - unzipfile(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "create_acl") == 0) - create_acl(dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - - /* GACL functions in grst_admin_gacl.c */ - - else if (strcmp(cmd, "show_acl") == 0) - show_acl(0, user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "admin_acl") == 0) - show_acl(1, user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "acl_history") == 0) - show_acl(2, user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd, "revert_acl") == 0) - revert_acl(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - //show_acl(2, user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"new_entry_form")==0) - new_entry_form(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"new_entry")==0) - new_entry(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"del_entry_sure")==0) - del_entry_sure(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"del_entry")==0) - del_entry(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"edit_entry_form")==0) - edit_entry_form(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"edit_entry")==0) - edit_entry(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"add_cred_form")==0) - add_cred_form(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"add_cred")==0) - add_cred(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"del_cred_sure")==0) - del_cred_sure(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - else if (strcmp(cmd,"del_cred")==0) - del_cred(user, dn, perm, help_uri, dir_path, file, dir_uri, admin_file); - - /* you what? */ - - else GRSThttpError("500 Internal Server Error"); -} diff --git a/org.gridsite.core/src/grst_gacl.c b/org.gridsite.core/src/grst_gacl.c deleted file mode 100644 index 13b46c8..0000000 --- a/org.gridsite.core/src/grst_gacl.c +++ /dev/null @@ -1,1154 +0,0 @@ -/* - Copyright (c) 2002-3, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ -/*---------------------------------------------------------------* - * For more information about GridSite: http://www.gridsite.org/ * - *---------------------------------------------------------------*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif -#include - -#include -#include -#include - -#include "gridsite.h" - -/* * - * Global variables, shared by all GACL functions by private to libgacl * - * */ - -char *grst_perm_syms[] = { "none", - "read", - "exec", - "list", - "write", - "admin", - NULL }; - -GRSTgaclPerm grst_perm_vals[] = { GRST_PERM_NONE, - GRST_PERM_READ, - GRST_PERM_EXEC, - GRST_PERM_LIST, - GRST_PERM_WRITE, - GRST_PERM_ADMIN, - -1 }; - -int GRSTgaclInit(void) -{ - xmlInitParser(); - - LIBXML_TEST_VERSION - - xmlKeepBlanksDefault(0); - - return 1; -} - -/* * - * Functions to manipulate GRSTgaclCred structures * - * */ - -GRSTgaclCred *GRSTgaclCredNew(char *type) -/* - GRSTgaclCredNew - allocate a new GRSTgaclCred structure, and return - it's pointer or NULL on (malloc) error. -*/ -{ - GRSTgaclCred *newcred; - - if (type == NULL) return NULL; - - newcred = malloc(sizeof(GRSTgaclCred)); - if (newcred == NULL) return NULL; - - newcred->type = strdup(type); - newcred->delegation = 0; - newcred->firstname = NULL; - newcred->next = NULL; - - return newcred; -} - -int GRSTgaclCredAddValue(GRSTgaclCred *cred, char *rawname, char *rawvalue) -/* - GRSTgaclCredAddValue - add a name/value pair to a GRSTgaclCred -*/ -{ - int i; - char *name, *value; - GRSTgaclNamevalue *p; - - name = strdup(rawname); - - /* no leading or trailing space in value */ - - value = rawvalue; - while ((*value != '\0') && isspace(*value)) ++value; - - value = strdup(value); - - for (i=strlen(value) - 1; (i >= 0) && isspace(value[i]); --i) value[i]='\0'; - - if (cred->firstname == NULL) - { - cred->firstname = malloc(sizeof (GRSTgaclNamevalue)); - (cred->firstname)->name = name; - (cred->firstname)->value = value; - (cred->firstname)->next = NULL; - } - else - { - p = cred->firstname; - - while (p->next != NULL) p = (GRSTgaclNamevalue *) p->next; - - p->next = malloc(sizeof(GRSTgaclNamevalue)); - ((GRSTgaclNamevalue *) p->next)->name = name; - ((GRSTgaclNamevalue *) p->next)->value = value; - ((GRSTgaclNamevalue *) p->next)->next = NULL; - } - - return 1; -} - -static int GRSTgaclNamevalueFree(GRSTgaclNamevalue *p) -{ - if (p == NULL) return 1; - - if (p->next != NULL) - GRSTgaclNamevalueFree((GRSTgaclNamevalue *) p->next); - if (p->name != NULL) free(p->name); - if (p->value != NULL) free(p->value); - free(p); - - return 1; -} - -int GRSTgaclCredFree(GRSTgaclCred *cred) -/* - GRSTgaclCredFree - free memory structures of a GRSTgaclCred, - returning 1 always! -*/ -{ - if (cred == NULL) return 1; - - GRSTgaclNamevalueFree(cred->firstname); - if (cred->type != NULL) free(cred->type); - free(cred); - - return 1; -} - -static int GRSTgaclCredsFree(GRSTgaclCred *firstcred) -/* - GRSTgaclCredsFree - free a cred and all the creds in its *next chain -*/ -{ - if (firstcred == NULL) return 0; - - if (firstcred->next != NULL) GRSTgaclCredsFree(firstcred->next); - - return GRSTgaclCredFree(firstcred); -} - -static int GRSTgaclCredInsert(GRSTgaclCred *firstcred, GRSTgaclCred *newcred) -/* - GRSTgaclCredInsert - insert a cred in the *next chain of firstcred - - FOR THE MOMENT THIS JUST APPENDS! -*/ -{ - if (firstcred == NULL) return 0; - - if (firstcred->next == NULL) - { - firstcred->next = newcred; - return 1; - } - - return GRSTgaclCredInsert(firstcred->next, newcred); -} - -int GRSTgaclEntryAddCred(GRSTgaclEntry *entry, GRSTgaclCred *cred) -/* - GRSTaddCred - add a new credential to an existing entry, returning 1 - on success or 0 on error -*/ -{ - if (entry == NULL) return 0; - - if (entry->firstcred == NULL) - { - entry->firstcred = cred; - return 1; - } - else return GRSTgaclCredInsert(entry->firstcred, cred); -} - -static int GRSTgaclCredRemoveCred(GRSTgaclCred *firstcred, GRSTgaclCred *oldcred) -/* - (Private) - - GRSTgaclCredRemoveCred - remove a cred in the *next chain of firstcred - and relink the chain -*/ -{ - if (firstcred == NULL) return 0; - -// yeah, I know -} - -int GRSTgaclEntryDelCred(GRSTgaclEntry *entry, GRSTgaclCred *cred) -/* - GRSTgaclEntryDelCred - remove a new cred from an entry, returning 1 - on success (or absense) or 0 on error. -*/ -{ - if (entry == NULL) return 0; - - return GRSTgaclCredRemoveCred(entry->firstcred, cred); -} - -int GRSTgaclCredPrint(GRSTgaclCred *cred, FILE *fp) -/* - GRSTgaclCredPrint - print a credential and any name-value pairs is contains -*/ -{ - char *q; - GRSTgaclNamevalue *p; - - if (cred->firstname != NULL) - { - fprintf(fp, "<%s>\n", cred->type); - - p = cred->firstname; - - do { - fprintf(fp, "<%s>", p->name); - - for (q=p->value; *q != '\0'; ++q) - if (*q == '<') fputs("<", fp); - else if (*q == '>') fputs(">", fp); - else if (*q == '&') fputs("&" , fp); - else if (*q == '\'') fputs("'", fp); - else if (*q == '"') fputs(""", fp); - else fputc(*q, fp); - - fprintf(fp, "\n", p->name); - - p = (GRSTgaclNamevalue *) p->next; - - } while (p != NULL); - - fprintf(fp, "\n", cred->type); - } - else fprintf(fp, "<%s/>\n", cred->type); - - return 1; -} - -/* * - * Functions to manipulate GRSTgaclEntry structures * - * */ - -GRSTgaclEntry *GRSTgaclEntryNew(void) -/* - GRSTgaclEntryNew - allocate space for a new entry, returning its pointer - or NULL on failure. -*/ -{ - GRSTgaclEntry *newentry; - - newentry = (GRSTgaclEntry *) malloc(sizeof(GRSTgaclEntry)); - if (newentry == NULL) return NULL; - - newentry->firstcred = NULL; - newentry->allowed = 0; - newentry->denied = 0; - newentry->next = NULL; - - return newentry; -} - -int GRSTgaclEntryFree(GRSTgaclEntry *entry) -/* - GRSTgaclEntryFree - free up space used by an entry (always returns 1) -*/ -{ - int i; - - if (entry == NULL) return 1; - - GRSTgaclCredsFree(entry->firstcred); - - free(entry); - - return 1; -} - -static int GRSTgaclEntriesFree(GRSTgaclEntry *entry) -/* - GRSTgaclEntriesFree - free up entry and all entries linked to in its *next - chain -*/ -{ - if (entry == NULL) return 0; - - if (entry->next != NULL) GRSTgaclEntriesFree(entry->next); - - return GRSTgaclEntryFree(entry); -} - -static int GRSTgaclEntryInsert(GRSTgaclEntry *firstentry, GRSTgaclEntry *newentry) -/* - GRSTgaclEntryInsert - insert an entry in the *next chain of firstentry - - FOR THE MOMENT THIS JUST APPENDS -*/ -{ - if (firstentry == NULL) return 0; - - if (firstentry->next == NULL) - { - firstentry->next = newentry; - return 1; - } - - return GRSTgaclEntryInsert(firstentry->next, newentry); -} - -int GRSTgaclAclAddEntry(GRSTgaclAcl *acl, GRSTgaclEntry *entry) -/* - GRSTgaclAclAddEntry - add a new entry to an existing acl, returning 1 - on success or 0 on error -*/ -{ - if (acl == NULL) return 0; - - if (acl->firstentry == NULL) - { - acl->firstentry = entry; - return 1; - } - else return GRSTgaclEntryInsert(acl->firstentry, entry); -} - -int GRSTgaclEntryPrint(GRSTgaclEntry *entry, FILE *fp) -{ - GRSTgaclCred *cred; - GRSTgaclPerm i; - - fputs("\n", fp); - - for (cred = entry->firstcred; cred != NULL; cred = cred->next) - GRSTgaclCredPrint(cred, fp); - - if (entry->allowed) - { - fputs("", fp); - - for (i=GRST_PERM_READ; i <= GRST_PERM_ADMIN; ++i) - if ((entry->allowed) & i) GRSTgaclPermPrint(i, fp); - - fputs("\n", fp); - } - - - if (entry->denied) - { - fputs("", fp); - - for (i=GRST_PERM_READ; i <= GRST_PERM_ADMIN; ++i) - if (entry->denied & i) GRSTgaclPermPrint(i, fp); - - fputs("\n", fp); - } - - fputs("\n", fp); - - return 1; -} - -/* * - * Functions to manipulate GRSTgaclPerm items * - * */ - -int GRSTgaclPermPrint(GRSTgaclPerm perm, FILE *fp) -{ - GRSTgaclPerm i; - - for (i=GRST_PERM_READ; grst_perm_syms[i] != NULL; ++i) - if (perm == grst_perm_vals[i]) - { - fprintf(fp, "<%s/>", grst_perm_syms[i]); - return 1; - } - - return 0; -} - -int GRSTgaclEntryAllowPerm(GRSTgaclEntry *entry, GRSTgaclPerm perm) -{ - entry->allowed = entry->allowed | perm; - - return 1; -} - -int GRSTgaclEntryUnallowPerm(GRSTgaclEntry *entry, GRSTgaclPerm perm) -{ - entry->allowed = entry->allowed & ~perm; - - return 1; -} - -int GRSTgaclEntryDenyPerm(GRSTgaclEntry *entry, GRSTgaclPerm perm) -{ - entry->denied = entry->denied | perm; - - return 1; -} - -int GRSTgaclEntryUndenyPerm(GRSTgaclEntry *entry, GRSTgaclPerm perm) -{ - entry->denied = entry->denied & ~perm; - - return 1; -} - -char *GRSTgaclPermToChar(GRSTgaclPerm perm) -/* - GRSTgaclPermToChar - return char * or NULL corresponding to most significant - set bit of perm. -*/ -{ - char *p = NULL; - GRSTgaclPerm i; - - for (i=0; grst_perm_syms[i] != NULL; ++i) - if (perm & grst_perm_vals[i]) p = grst_perm_syms[i]; - - return p; -} - -GRSTgaclPerm GRSTgaclPermFromChar(char *s) -/* - GRSTgaclPermToChar - return access perm corresponding to symbol s[] -*/ -{ - GRSTgaclPerm i; - - for (i=0; grst_perm_syms[i] != NULL; ++i) - if (strcasecmp(grst_perm_syms[i], s) == 0) return grst_perm_vals[i]; - - return -1; -} - -/* * - * Functions to manipulate GRSTgaclAcl structures * - * */ - -GRSTgaclAcl *GRSTgaclAclNew(void) -/* - GRSTgaclAclNew - allocate a new acl and return its pointer (or NULL - on failure.) -*/ -{ - GRSTgaclAcl *newacl; - - newacl = (GRSTgaclAcl *) malloc(sizeof(GRSTgaclAcl)); - if (newacl == NULL) return NULL; - - newacl->firstentry = NULL; - - return newacl; -} - -int GRSTgaclAclFree(GRSTgaclAcl *acl) -/* - GRSTgaclAclFree - free up space used by *acl. Always returns 1. -*/ -{ - if (acl == NULL) return 1; - - GRSTgaclEntriesFree(acl->firstentry); - - return 1; -} - -int GRSTgaclAclPrint(GRSTgaclAcl *acl, FILE *fp) -{ - GRSTgaclEntry *entry; - - fputs("\n", fp); - - for (entry = acl->firstentry; entry != NULL; entry = entry->next) - GRSTgaclEntryPrint(entry, fp); - - fputs("\n", fp); - - return 1; -} - -int GRSTgaclAclSave(GRSTgaclAcl *acl, char *filename) -{ - int ret; - FILE *fp; - - fp = fopen(filename, "w"); - if (fp == NULL) return 0; - - fputs("\n", fp); - - ret = GRSTgaclAclPrint(acl, fp); - - fclose(fp); - - return ret; -} - -/* * - * Functions for loading and parsing XML using libxml * - * */ - -// need to check these for libxml memory leaks? - what needs to be freed? - -static GRSTgaclCred *GRSTgaclCredParse(xmlNodePtr cur) -/* - GRSTgaclCredParse - parse a credential stored in the libxml structure cur, - returning it as a pointer or NULL on error. -*/ -{ - xmlNodePtr cur2; - GRSTgaclCred *cred; - - cred = GRSTgaclCredNew((char *) cur->name); - - cred->firstname = NULL; - cred->next = NULL; - - for (cur2 = cur->xmlChildrenNode; cur2 != NULL; cur2=cur2->next) - { - GRSTgaclCredAddValue(cred, (char *) cur2->name, - (char *) xmlNodeGetContent(cur2)); - } - - return cred; -} - -static GRSTgaclEntry *GRSTgaclEntryParse(xmlNodePtr cur) -/* - GRSTgaclEntryParse - parse an entry stored in the libxml structure cur, - returning it as a pointer or NULL on error. -*/ -{ - int i; - xmlNodePtr cur2; - GRSTgaclEntry *entry; - GRSTgaclCred *cred; - GRSTgaclPerm perm; - - if (xmlStrcmp(cur->name, (const xmlChar *) "entry") != 0) return NULL; - - cur = cur->xmlChildrenNode; - - entry = GRSTgaclEntryNew(); - - while (cur != NULL) - { - if (xmlStrcmp(cur->name, (const xmlChar *) "allow") == 0) - { - for (cur2 = cur->xmlChildrenNode; cur2 != NULL; cur2=cur2->next) - for (i=0; grst_perm_syms[i] != NULL; ++i) - if (xmlStrcmp(cur2->name, - (const xmlChar *) grst_perm_syms[i]) == 0) - GRSTgaclEntryAllowPerm(entry, grst_perm_vals[i]); - } - else if (xmlStrcmp(cur->name, (const xmlChar *) "deny") == 0) - { - for (cur2 = cur->xmlChildrenNode; cur2 != NULL; cur2=cur2->next) - for (i=0; grst_perm_syms[i] != NULL; ++i) - if (xmlStrcmp(cur2->name, - (const xmlChar *) grst_perm_syms[i]) == 0) - GRSTgaclEntryDenyPerm(entry, grst_perm_vals[i]); - } - else if ((cred = GRSTgaclCredParse(cur)) != NULL) - { - if (!GRSTgaclEntryAddCred(entry, cred)) - { - GRSTgaclCredFree(cred); - GRSTgaclEntryFree(entry); - return NULL; - } - } - else /* I cannot parse this - give up rather than get it wrong */ - { - GRSTgaclEntryFree(entry); - return NULL; - } - - cur=cur->next; - } - - return entry; -} - -GRSTgaclAcl *GRSTgaclAclLoadFile(char *filename) -{ - xmlDocPtr doc; - xmlNodePtr cur; - GRSTgaclAcl *acl; - GRSTgaclEntry *entry; - - doc = xmlParseFile(filename); - if (doc == NULL) return NULL; - - cur = xmlDocGetRootElement(doc); - - if (xmlStrcmp(cur->name, (const xmlChar *) "gacl")) - { - free(doc); - free(cur); - return NULL; - } - - cur = cur->xmlChildrenNode; - - acl = GRSTgaclAclNew(); - - while (cur != NULL) - { - entry = GRSTgaclEntryParse(cur); - if (entry == NULL) - { - GRSTgaclAclFree(acl); - xmlFreeDoc(doc); - return NULL; - } - - GRSTgaclAclAddEntry(acl, entry); - - cur=cur->next; - } - - xmlFreeDoc(doc); - return acl; -} - -int GRSTgaclFileIsAcl(char *pathandfile) -/* Return 1 if filename in *pathandfile starts GRST_ACL_FILE - Return 0 otherwise. */ -{ - char *filename; - - filename = rindex(pathandfile, '/'); - if (filename == NULL) filename = pathandfile; - else filename++; - - return (strncmp(filename, GRST_ACL_FILE, sizeof(GRST_ACL_FILE) - 1) == 0); -} - -char *GRSTgaclFileFindAclname(char *pathandfile) -/* Return malloc()ed ACL filename that governs the given file or directory - (for directories, the ACL file is in the directory itself), or NULL if none - can be found. */ -{ - int len; - char *path, *file, *p; - struct stat statbuf; - - len = strlen(pathandfile); - if (len == 0) return NULL; - - path = malloc(len + sizeof(GRST_ACL_FILE) + 2); - strcpy(path, pathandfile); - - if ((stat(path, &statbuf) == 0) && - S_ISDIR(statbuf.st_mode) && - (path[len-1] != '/')) - { - strcat(path, "/"); - ++len; - } - - if (path[len-1] != '/') - { - p = rindex(pathandfile, '/'); - if (p != NULL) - { - file = &p[1]; - p = rindex(path, '/'); - sprintf(p, "/%s:%s", GRST_ACL_FILE, file); - - if (stat(path, &statbuf) == 0) return path; - - *p = '\0'; /* otherwise strip off any filename */ - } - } - - while (path[0] != '\0') - { - strcat(path, "/"); - strcat(path, GRST_ACL_FILE); - - if (stat(path, &statbuf) == 0) return path; - - p = rindex(path, '/'); - *p = '\0'; /* strip off the / we added for ACL */ - - p = rindex(path, '/'); - if (p == NULL) break; /* must start without / and we there now ??? */ - - *p = '\0'; /* strip off another layer of / */ - } - - free(path); - return NULL; -} - -GRSTgaclAcl *GRSTgaclAclLoadforFile(char *pathandfile) -/* Return ACL that governs the given file or directory (for directories, - the ACL file is in the directory itself.) */ -{ - char *path; - GRSTgaclAcl *acl; - - path = GRSTgaclFileFindAclname(pathandfile); - - if (path != NULL) - { - acl = GRSTgaclAclLoadFile(path); - free(path); - return acl; - } - - return NULL; -} - -/* * - * Functions to create and query GACLuser * - * */ - -GRSTgaclUser *GRSTgaclUserNew(GRSTgaclCred *cred) -{ - GRSTgaclUser *user; - - if (cred == NULL) return NULL; - - user = malloc(sizeof(GRSTgaclUser)); - - if (user != NULL) user->firstcred = cred; - - user->dnlists = NULL; - - return user; -} - -int GRSTgaclUserFree(GRSTgaclUser *user) -{ - if (user == NULL) return 1; - - if (user->firstcred != NULL) GRSTgaclCredsFree(user->firstcred); - - if (user->dnlists != NULL) free(user->dnlists); - - free(user); - - return 1; -} - -int GRSTgaclUserAddCred(GRSTgaclUser *user, GRSTgaclCred *cred) -{ - GRSTgaclCred *crediter; - - if ((user == NULL) || (cred == NULL)) return 0; - - if (user->firstcred == NULL) - { - user->firstcred = cred; - cred->next = NULL; /* so cannot be used to add whole lists */ - return 1; - } - - crediter = user->firstcred; - - while (crediter->next != NULL) crediter = crediter->next; - - crediter->next = cred; - cred->next = NULL; /* so cannot be used to add whole lists */ - - return 1; -} - -int GRSTgaclUserHasCred(GRSTgaclUser *user, GRSTgaclCred *cred) -/* test if the user has the given credential */ -{ - GRSTgaclCred *crediter; - GRSTgaclNamevalue *usernamevalue, *crednamevalue; - - if (cred == NULL) return 0; - - if (strcmp(cred->type, "any-user") == 0) return 1; - - if (user == NULL) return 0; - - if (strcmp(cred->type, "dn-list") == 0) - { - if ((cred->firstname == NULL) || - (strcmp((cred->firstname)->name, "url") != 0) || - ((cred->firstname)->next != NULL)) return 0; - - return GRSTgaclDNlistHasUser((cred->firstname)->value, user); - } - - if (strcmp(cred->type, "dns") == 0) - { - if ((user->firstcred == NULL) || - ((user->firstcred)->firstname == NULL) || - (cred->firstname == NULL) || - (strcmp((cred->firstname)->name, "hostname") != 0) || - ((cred->firstname)->next != NULL)) return 0; - - for (crediter=user->firstcred; - crediter != NULL; - crediter = crediter->next) - if (strcmp(crediter->type, "dns") == 0) - { - if ((crediter->firstname == NULL) || - (strcmp((crediter->firstname)->name, "hostname") != 0)) return 0; - - return (fnmatch((cred->firstname)->value, - (crediter->firstname)->value, FNM_CASEFOLD) == 0); - } - - return 0; - } - - if (strcmp(cred->type, "auth-user") == 0) - { - if ((user->firstcred == NULL) || - ((user->firstcred)->firstname == NULL)) return 0; - - for (crediter=user->firstcred; - crediter != NULL; - crediter = crediter->next) - if (strcmp(crediter->type, "person") == 0) return 1; - - return 0; - } - - for (crediter=user->firstcred; crediter != NULL; crediter = crediter->next) - { - if (strcmp(crediter->type, cred->type) != 0) continue; - - if ((crediter->firstname == NULL) && - (cred->firstname == NULL)) return 1; - - if ((crediter->firstname == NULL) || - (cred->firstname == NULL)) continue; - - usernamevalue = crediter->firstname; - crednamevalue = cred->firstname; - - for (;;) - { - if (strcmp(usernamevalue->name,crednamevalue->name) != 0) break; - - if (strcmp(cred->type, "person") == 0) - { - if (GRSTx509NameCmp(usernamevalue->value, - crednamevalue->value) != 0) break; - } - else if (strcmp(usernamevalue->value, - crednamevalue->value) != 0) break; - - /* ok if cred list runs out before user's cred list */ - if (crednamevalue->next == NULL) return 1; - - /* but not ok if more names to match which user doesn't have */ - if (usernamevalue->next == NULL) break; - - crednamevalue = (GRSTgaclNamevalue *) crednamevalue->next; - usernamevalue = (GRSTgaclNamevalue *) usernamevalue->next; - } - } - - return 0; -} - -GRSTgaclCred *GRSTgaclUserFindCredtype(GRSTgaclUser *user, char *type) -/* find the first credential of a given type for this user */ -{ - GRSTgaclCred *cred; - - if (user == NULL) return NULL; - - cred = user->firstcred; - - while (cred != NULL) - { - if (strcmp(cred->type, type) == 0) return cred; - - cred = cred->next; - } - - return NULL; -} - -int GRSTgaclUserSetDNlists(GRSTgaclUser *user, char *dnlists) -{ - if ((user == NULL) || (dnlists == NULL)) return 0; - - if (user->dnlists != NULL) free(user->dnlists); - - user->dnlists = strdup(dnlists); - - return 1; -} - -/* * - * Functions to test for access perm of an individual * - * */ - -static char *recurse4file(char *dir, char *file, int recurse_level) -/* try to find file[] in dir[]. try subdirs if not found. - return full path to first found version or NULL on failure */ -{ - char *fullfilename, *fulldirname; - struct stat statbuf; - DIR *dirDIR; - struct dirent *file_ent; - - /* try to find in current directory */ - - asprintf(&fullfilename, "%s/%s", dir, file); - if (stat(fullfilename, &statbuf) == 0) return fullfilename; - free(fullfilename); - - /* maybe search in subdirectories */ - - if (recurse_level >= GRST_RECURS_LIMIT) return NULL; - - dirDIR = opendir(dir); - - if (dirDIR == NULL) return NULL; - - while ((file_ent = readdir(dirDIR)) != NULL) - { - if (file_ent->d_name[0] == '.') continue; - - asprintf(&fulldirname, "%s/%s", dir, file_ent->d_name); - - if ((stat(fulldirname, &statbuf) == 0) && - S_ISDIR(statbuf.st_mode) && - ((fullfilename = recurse4file(fulldirname, file, - recurse_level + 1)) != NULL)) - { - closedir(dirDIR); - return fullfilename; - } - - free(fulldirname); - } - - closedir(dirDIR); - - return NULL; -} - -int GRSTgaclDNlistHasUser(char *listurl, GRSTgaclUser *user) -{ - char *dn_lists_dirs, *dn_list_ptr, *enclisturl, *filename, *dirname, - line[512], *p; - FILE *fp; - GRSTgaclCred *cred; - - if ((listurl == NULL) || (user == NULL)) return 0; - - enclisturl = GRSThttpUrlEncode(listurl); - - if (user->dnlists != NULL) p = user->dnlists; - else p = getenv("GRST_DN_LISTS"); - - if (p == NULL) p = GRST_DN_LISTS; - dn_lists_dirs = strdup(p); /* we need to keep this for free() later! */ - dn_list_ptr = dn_lists_dirs; /* copy, for naughty function strsep() */ - - while ((dirname = strsep(&dn_list_ptr, ":")) != NULL) - { - filename = recurse4file(dirname, enclisturl, 0); - if (filename == NULL) continue; - - fp = fopen(filename, "r"); - free(filename); - - if (fp == NULL) continue; - - while (fgets(line, sizeof(line), fp) != NULL) - { - p = index(line, '\n'); - if (p != NULL) *p = '\0'; - - cred = user->firstcred; - - while (cred != NULL) - { - if ((strcmp(cred->type, "person") == 0) && - (cred->firstname != NULL) && - (strcmp("dn", (cred->firstname)->name) == 0) && - (GRSTx509NameCmp(line, (cred->firstname)->value) == 0)) - { - fclose(fp); - free(dn_lists_dirs); - free(enclisturl); - return 1; - } - - cred = cred->next; - } - } - - fclose(fp); - } - - free(dn_lists_dirs); - free(enclisturl); - - return 0; -} - -GRSTgaclPerm GRSTgaclAclTestUser(GRSTgaclAcl *acl, GRSTgaclUser *user) -/* - GACLgaclAclTestUser - return bit fields depending on access perms user has - for given acl. All zero for no access. If *user is - NULL, matching to "any-user" will still work. -*/ -{ - int flag, onlyanyuser; - GRSTgaclPerm allowperms = 0, denyperms = 0, allowed; - GRSTgaclEntry *entry; - GRSTgaclCred *cred, *usercred; - - if (acl == NULL) return 0; - - for (entry = acl->firstentry; entry != NULL; entry = entry->next) - { - flag = 1; /* begin by assuming this entry applies to us */ - onlyanyuser = 1; /* begin by assuming just */ - - /* now go through creds, checking they all do apply to us */ - - for (cred = entry->firstcred; cred != NULL; cred = cred->next) - if (!GRSTgaclUserHasCred(user, cred)) flag = 0; - else if (strcmp(cred->type, "any-user") != 0) onlyanyuser = 0; - - if (!flag) continue; /* flag false if a subtest failed */ - - /* does apply to us, so we remember this entry's perms */ - - /* we dont allow Write or Admin on the basis of any-user alone */ - - allowed = entry->allowed; - - if (onlyanyuser) - allowed = entry->allowed & ~GRST_PERM_WRITE & ~GRST_PERM_ADMIN; - else allowed = entry->allowed; - - allowperms = allowperms | allowed; - denyperms = denyperms | entry->denied; - } - - return (allowperms & (~ denyperms)); - /* for each perm type, any deny we saw kills any allow */ -} - -GRSTgaclPerm GRSTgaclAclTestexclUser(GRSTgaclAcl *acl, GRSTgaclUser *user) -/* - GRSTgaclAclTestexclUser - - return bit fields depending on ALLOW perms OTHER users - have for given acl. All zero if they have no access. - (used for testing if a user has exclusive access) -*/ -{ - int flag; - GRSTgaclPerm perm = 0; - GRSTgaclEntry *entry; - GRSTgaclCred *cred; - - if (acl == NULL) return 0; - - for (entry = acl->firstentry; entry != NULL; entry = entry->next) - { - flag = 0; /* flag will be set if cred implies other users */ - - for (cred = entry->firstcred; cred != NULL; cred = cred->next) - { - if (strcmp(cred->type, "person") != 0) - /* if we ever add support for other person-specific credentials, - they must also be recognised here */ - { - flag = 1; - break; - } - - if (!GRSTgaclUserHasCred(user, cred)) - /* if user doesnt have this person credential, assume - it refers to a different individual */ - { - flag = 1; - break; - } - } - - if (flag) perm = perm | entry->allowed; - } - - return perm; -} - -/* - Wrapper functions for gridsite-gacl.h support of legacy API -*/ - -GRSTgaclEntry *GACLparseEntry(xmlNodePtr cur) -{ - return GRSTgaclEntryParse(cur); -} diff --git a/org.gridsite.core/src/grst_http.c b/org.gridsite.core/src/grst_http.c deleted file mode 100644 index c7b375e..0000000 --- a/org.gridsite.core/src/grst_http.c +++ /dev/null @@ -1,407 +0,0 @@ -/* - Copyright (c) 2002-3, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -#ifndef VERSION -#define VERSION "x.x.x" -#endif - -#define _GNU_SOURCE -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "gridsite.h" - -void GRSThttpBodyInit(GRSThttpBody *thisbody) -{ - thisbody->size = 0; /* simple, but we don't expose internals to callers */ -} - -void GRSThttpPrintf(GRSThttpBody *thisbody, char *fmt, ...) -/* append printf() style format and arguments to *thisbody. - This requires vasprintf from glibc!! */ -{ - char *p; - size_t size; - va_list args; - - va_start(args, fmt); - size = vasprintf(&p, fmt, args); - va_end(args); - - if (size == 0) free(p); /* don't need to bother in this case */ - else if (size > 0) - { - if (thisbody->size == 0) /* need to initialise */ - { - thisbody->first = (GRSThttpCharsList *)malloc(sizeof(GRSThttpCharsList)); - thisbody->first->text = p; - thisbody->first->next = NULL; - - thisbody->last = thisbody->first; - thisbody->size = size; - } - else - { - thisbody->last->next = (GRSThttpCharsList *) - malloc(sizeof(GRSThttpCharsList)); - ((GRSThttpCharsList *) thisbody->last->next)->text = p; - ((GRSThttpCharsList *) thisbody->last->next)->next = NULL; - - thisbody->last = thisbody->last->next; - thisbody->size = thisbody->size + size; - } - } -} - -int GRSThttpCopy(GRSThttpBody *thisbody, char *file) -/* - copy a whole file, named file[], into the body output buffer, returning - 1 if file was found and copied ok, or 0 otherwise. -*/ -{ - int fd, len; - char c, *p; - struct stat statbuf; - - fd = open(file, O_RDONLY); - - if (fd == -1) return 0; - - if (fstat(fd, &statbuf) != 0) - { - close(fd); - return 0; - } - - p = malloc(statbuf.st_size + 1); - - if (p == NULL) - { - close(fd); - return 0; - } - - len = read(fd, p, statbuf.st_size); - p[len] = '\0'; - - close(fd); - - if (thisbody->size == 0) /* need to initialise */ - { - thisbody->first = (GRSThttpCharsList *) malloc(sizeof(GRSThttpCharsList)); - thisbody->first->text = p; - thisbody->first->next = NULL; - - thisbody->last = thisbody->first; - thisbody->size = len; - } - else - { - thisbody->last->next=(GRSThttpCharsList *)malloc(sizeof(GRSThttpCharsList)); - ((GRSThttpCharsList *) thisbody->last->next)->text = p; - ((GRSThttpCharsList *) thisbody->last->next)->next = NULL; - - thisbody->last = thisbody->last->next; - thisbody->size = thisbody->size + len; - } - - return 1; -} - -void GRSThttpWriteOut(GRSThttpBody *thisbody) -/* output Content-Length header, blank line then whole of the body to - standard output */ -{ - GRSThttpCharsList *p; - - printf("Content-Length: %d\n\n", thisbody->size); - - p = thisbody->first; - - while (p != NULL) - { - fputs(p->text, stdout); - - p = p->next; - } -} - -int GRSThttpPrintHeaderFooter(GRSThttpBody *bp, char *file, char *headfootname) -/* - try to print Header or Footer appropriate for absolute path file[], - returning 1 rather than 0 if found. -*/ -{ - int found = 0; - char *pathfile, *p; - struct stat statbuf; - - pathfile = malloc(strlen(file) + strlen(headfootname) + 2); - strcpy(pathfile, file); - - if ((pathfile[strlen(pathfile) - 1] != '/') && - (stat(pathfile, &statbuf) == 0) && - S_ISDIR(statbuf.st_mode)) strcat(pathfile, "/"); - - for (;;) - { - p = rindex(pathfile, '/'); - if (p == NULL) break; - p[1] = '\0'; - strcat(p, headfootname); - - if (stat(pathfile, &statbuf) == 0) - { - found = GRSThttpCopy(bp, pathfile); - break; - } - - p[0] = '\0'; - } - - free(pathfile); - return found; -} - -char *GRSThttpGetCGI(char *name) -/* - Return a malloc()ed copy of CGI form parameter identified by name[], - either received by QUERY_STRING (via GET) or on stdin (via POST). - Caller must free() the returned string itself. If name[] is not found, - an empty NUL-terminated malloc()ed string is returned. name[] has any - URL-encoding reversed. -*/ -{ - char *p, *namepattern, *valuestart, *returnvalue, *querystring; - int c, i, j, n, contentlength = 0; - static char *cgiposted = NULL; - size_t size_needed; - - if (cgiposted == NULL) /* have to initialise cgiposted */ - { - p = getenv("CONTENT_LENGTH"); - if (p != NULL) sscanf(p, "%d", &contentlength); - - querystring = getenv("REDIRECT_QUERY_STRING"); - if (querystring == NULL) querystring = getenv("QUERY_STRING"); - - if (querystring == NULL) cgiposted = malloc(contentlength + 3); - else cgiposted = malloc(contentlength + strlen(querystring) + 4); - - cgiposted[0] = '&'; - - for (i = 1; i <= contentlength; ++i) - { - c = getchar(); - if (c == EOF) break; - cgiposted[i] = c; - } - - cgiposted[i] = '&'; - cgiposted[i+1] = '\0'; - - if (querystring != NULL) - { - strcat(cgiposted, querystring); - strcat(cgiposted, "&"); - } - } - - namepattern = malloc(strlen(name) + 3); - sprintf(namepattern, "&%s=", name); - - p = strstr(cgiposted, namepattern); - free(namepattern); - if (p == NULL) return strdup(""); - - valuestart = &p[strlen(name) + 2]; - - for (n=0; valuestart[n] != '&'; ++n) ; - - returnvalue = malloc(n + 1); - - j=0; - - for (i=0; i < n; ++i) - { - if ((i < n - 2) && (valuestart[i] == '%')) /* url encoded as %HH */ - { - returnvalue[j] = 0; - - if (isdigit(valuestart[i+1])) - returnvalue[j] += 16 * (valuestart[i+1] - '0'); - else if (isalpha(valuestart[i+1])) - returnvalue[j] += 16 * (10 + tolower(valuestart[i+1]) - 'a'); - - if (isdigit(valuestart[i+2])) - returnvalue[j] += valuestart[i+2] - '0'; - else if (isalpha(valuestart[i+2])) - returnvalue[j] += 10 + tolower(valuestart[i+2]) - 'a'; - - i = i + 2; - } - else if (valuestart[i] == '+') returnvalue[j] = ' '; - else returnvalue[j] = valuestart[i]; - - if (returnvalue[j] == '\r') continue; /* CR/LF -> LF */ - ++j; - } - - returnvalue[j] = '\0'; - - return returnvalue; -} - -/* * - * Utility functions * - * */ - -char *GRSThttpUrlDecode(char *in) -{ - int i, j, n; - char *out; - - n = strlen(in); - out = malloc(n + 1); - - j=0; - - for (i=0; i < n; ++i) - { - if ((i < n - 2) && (in[i] == '%')) /* url encoded as %HH */ - { - out[j] = 0; - - if (isdigit(in[i+1])) - out[j] += 16 * (in[i+1] - '0'); - else if (isalpha(in[i+1])) - out[j] += 16 * (10 + tolower(in[i+1]) - 'a'); - - if (isdigit(in[i+2])) - out[j] += in[i+2] - '0'; - else if (isalpha(in[i+2])) - out[j] += 10 + tolower(in[i+2]) - 'a'; - - i = i + 2; - } - else if (in[i] == '+') out[j] = ' '; - else out[j] = in[i]; - - ++j; - } - - out[j] = '\0'; - - return out; -} - -char *GRSThttpUrlEncode(char *in) -/* Return a pointer to a malloc'd string holding a URL-encoded (RFC 1738) - version of *in. Only A-Z a-z 0-9 . _ - are passed through unmodified. - (DN's processed by GRSThttpUrlEncode can be used as valid Unix filenames, - assuming they do not exceed restrictions on filename length.) */ -{ - char *out, *p, *q; - - out = malloc(3*strlen(in) + 1); - - p = in; - q = out; - - while (*p != '\0') - { - if (isalnum(*p) || (*p == '.') || (*p == '_') || (*p == '-')) - { - *q = *p; - ++q; - } - else - { - sprintf(q, "%%%2X", *p); - q = &q[3]; - } - - ++p; - } - - *q = '\0'; - return out; -} - -char *GRSThttpUrlMildencode(char *in) -/* Return a pointer to a malloc'd string holding a partially URL-encoded - version of *in. "Partially" means that A-Z a-z 0-9 . = - _ @ and / - are passed through unmodified. (DN's processed by GRSThttpUrlMildencode() - can be used as valid Unix paths+filenames if you are prepared to - create or simulate the resulting /X=xyz directories.) */ -{ - char *out, *p, *q; - - out = malloc(3*strlen(in) + 1); - - p = in; - q = out; - - while (*p != '\0') - { - if (isalnum(*p) || (*p == '.') || (*p == '=') || (*p == '-') - || (*p == '/') || (*p == '@') || (*p == '_')) - { - *q = *p; - ++q; - } - else if (*p == ' ') - { - *q = '+'; - ++q; - } - else - { - sprintf(q, "%%%2X", *p); - q = &q[3]; - } - - ++p; - } - - *q = '\0'; - return out; -} diff --git a/org.gridsite.core/src/grst_x509.c b/org.gridsite.core/src/grst_x509.c deleted file mode 100644 index 37b60e6..0000000 --- a/org.gridsite.core/src/grst_x509.c +++ /dev/null @@ -1,1398 +0,0 @@ -/* - Copyright (c) 2002-4, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. - - --------------------------------------------------------------- - For more information about GridSite: http://www.gridsite.org/ - --------------------------------------------------------------- -*/ - -#define _GNU_SOURCE - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#ifdef GRST_VOMS_SUPPORT -#include -#endif - -#include "gridsite.h" - -#define GRST_KEYSIZE 512 -#define GRST_PROXYCACHE "/../proxycache/" -#define GRST_MAX_CHAIN_LEN 9 - -/// Compare X509 Distinguished Name strings -int GRSTx509NameCmp(char *a, char *b) -/** - * This function attempts to do with string representations what - * would ideally be done with OIDs/values. In particular, we equate - * "/Email=" == "/emailAddress=" to deal with this important change - * between OpenSSL 0.9.6 and 0.9.7. - * Other than that, it is currently the same as ordinary strcmp(3). - */ -{ - int ret; - char *aa, *bb, *p; - - aa = strdup(a); - while ((p = strstr(aa, "/emailAddress=")) != NULL) - { - memmove(&p[6], &p[13], strlen(&p[13]) + 1); - p[1] = 'E'; - } - - bb = strdup(b); - while ((p = strstr(bb, "/emailAddress=")) != NULL) - { - memmove(&p[6], &p[13], strlen(&p[13]) + 1); - p[1] = 'E'; - } - - ret = strcmp(aa, bb); - - free(aa); - free(bb); - - return ret; -} - - -/// Check critical extensions -/** - * Returning GRST_RET_OK if all of extensions are known to us or - * OpenSSL; GRST_REF_FAILED otherwise. - * - * Since this function relies on functionality (X509_supported_extension) - * introduced in 0.9.7, then we do nothing and report an error - * (GRST_RET_FAILED) if one of the associated defines - * (X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) is absent. - */ - -int GRSTx509KnownCriticalExts(X509 *cert) -{ - int i; - char s[80]; - X509_EXTENSION *ex; - -#ifdef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION - for (i = 0; i < X509_get_ext_count(cert); ++i) - { - ex = X509_get_ext(cert, i); - - if (X509_EXTENSION_get_critical(ex) && - !X509_supported_extension(ex)) - { - OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(ex), 1); - - if (strcmp(s, GRST_PROXYCERTINFO_OID) != 0) return GRST_RET_FAILED; - } - } - - return GRST_RET_OK; -#else - return GRST_RET_FAILED; -#endif -} - -/// ASN1 time string (in a char *) to time_t -/** - * (Use ASN1_STRING_data() to convert ASN1_GENERALIZEDTIME to char * if - * necessary) - */ - -time_t GRSTasn1TimeToTimeT(char *asn1time) -{ - char zone; - struct tm time_tm; - - if ((sscanf(asn1time, "%02d%02d%02d%02d%02d%02d%c", - &(time_tm.tm_year), - &(time_tm.tm_mon), - &(time_tm.tm_mday), - &(time_tm.tm_hour), - &(time_tm.tm_min), - &(time_tm.tm_sec), - &zone) != 7) || (zone != 'Z')) return 0; /* dont understand */ - - /* time format fixups */ - - if (time_tm.tm_year < 90) time_tm.tm_year += 100; - --(time_tm.tm_mon); - - return timegm(&time_tm); -} - -/// Check if certificate can be used as a CA to sign standard X509 certs -/* - * Return GRST_RET_OK if true; GRST_RET_FAILED if not. - */ - -int GRSTx509IsCA(X509 *cert) -{ - int idret, purpose_id; - - purpose_id = X509_PURPOSE_get_by_sname("sslclient"); - - /* final argument to X509_check_purpose() is whether to check for CAness */ - - if (X509_check_purpose(cert, purpose_id + X509_PURPOSE_MIN, 1)) - return GRST_RET_OK; - else return GRST_RET_FAILED; -} - -/// Check certificate chain for GSI proxy acceptability. -/** - * Returns X509_V_OK/GRST_RET_OK if valid; OpenSSL X509 errors otherwise. - * - * Inspired by GSIcheck written by Mike Jones, SVE, Manchester Computing, - * The University of Manchester. - * - * The GridSite version handles old and new style Globus proxies, and - * proxies derived from user certificates issued with "X509v3 Basic - * Constraints: CA:FALSE" (eg UK e-Science CA) - * - * We do not check chain links between certs here: this is done by - * GRST_check_issued/X509_check_issued in mod_ssl's ssl_engine_init.c - * - * TODO: we do not yet check ProxyCertInfo and ProxyCertPolicy extensions - * (although via GRSTx509KnownCriticalExts() we can accept them.) - */ - -int GRSTx509CheckChain(int *first_non_ca, X509_STORE_CTX *ctx) -{ - STACK_OF(X509) *certstack; /* Points to the client's cert chain */ - X509 *cert; /* Points to the client's cert */ - int depth; /* Depth of cert chain */ - size_t len,len2; /* Lengths of issuer and cert DN */ - int IsCA; /* Holds whether cert is allowed to sign */ - int prevIsCA; /* Holds whether previous cert in chain is - allowed to sign */ - int prevIsLimited; /* previous cert was proxy and limited */ - int i,j; /* Iteration variables */ - char *cert_DN; /* Pointer to current-certificate-in-chain's - DN */ - char *issuer_DN; /* Pointer to - issuer-of-current-cert-in-chain's DN */ - char *proxy_part_DN; /* Pointer to end part of current-cert-in-chain - maybe eg "/CN=proxy" */ - time_t now; - - time(&now); - - *first_non_ca = 0; /* set to something predictable if things fail */ - - /* Check for context */ - if (!ctx) return X509_V_ERR_INVALID_CA; - /* Can't GSI-verify if there is no context. Here and throughout this - function we report all errors as X509_V_ERR_INVALID_CA. */ - - /* Set necessary preliminary values */ - IsCA = TRUE; /* =prevIsCA - start from a CA */ - prevIsLimited = 0; - - /* Get the client cert chain */ - certstack = X509_STORE_CTX_get_chain(ctx); /* Get the client's chain */ - depth = sk_X509_num(certstack); /* How deep is that chain? */ - - /* Check the client chain */ - for (i=depth-1; i >= 0; --i) - /* loop through client-presented chain starting at CA end */ - { - prevIsCA=IsCA; - - /* Check for X509 certificate and point to it with 'cert' */ - if (cert = sk_X509_value(certstack, i)) - { - /* we check times and reject immediately if invalid */ - - if (now < - GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(cert)))) - return X509_V_ERR_INVALID_CA; - - if (now > - GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(cert)))) - return X509_V_ERR_INVALID_CA; - - /* If any forebear certificate is not allowed to sign we must - assume all decendents are proxies and cannot sign either */ - if (prevIsCA) - { - /* always treat the first cert (from the CA files) as a CA */ - if (i == depth-1) IsCA = TRUE; - /* check if this cert is valid CA for signing certs */ - else IsCA = (GRSTx509IsCA(cert) == GRST_RET_OK); - - if (!IsCA) *first_non_ca = i; - } - else - { - IsCA = FALSE; - /* Force proxy check next iteration. Important because I can - sign any CA I create! */ - } - - cert_DN = X509_NAME_oneline(X509_get_subject_name(cert),NULL,0); - issuer_DN = X509_NAME_oneline(X509_get_issuer_name(cert),NULL,0); - len = strlen(cert_DN); - len2 = strlen(issuer_DN); - - /* issuer didn't have CA status, so this is (at best) a proxy: - check for bad proxy extension*/ - - if (!prevIsCA) - { - if (prevIsLimited) /* we reject proxies of limited proxies! */ - return X509_V_ERR_INVALID_CA; - - /* User not allowed to sign shortened DN */ - if (len2 > len) return X509_V_ERR_INVALID_CA; - - /* Proxy subject must begin with issuer. */ - if (strncmp(cert_DN, issuer_DN, len2) != 0) - return X509_V_ERR_INVALID_CA; - - /* Set pointer to end of base DN in cert_DN */ - proxy_part_DN = &cert_DN[len2]; - - /* First attempt at support for Old and New style GSI - proxies: /CN=anything is ok for now */ - if (strncmp(proxy_part_DN, "/CN=", 4) != 0) - return X509_V_ERR_INVALID_CA; - - if ((strncmp(proxy_part_DN, "/CN=limited proxy", 17) == 0) && - (i > 0)) prevIsLimited = 1; /* ready for next cert ... */ - } - } - } - - /* Check cert whose private key is being used by client. If previous in - chain is not allowed to be a CA then need to check this final cert for - valid proxy-icity too */ - if (!prevIsCA) - { - if (prevIsLimited) return X509_V_ERR_INVALID_CA; - /* we do not accept proxies signed by limited proxies */ - - if (cert = sk_X509_value(certstack, 0)) - { - /* Load DN & length of DN and either its issuer or the - first-bad-issuer-in-chain */ - cert_DN = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); - issuer_DN = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0); - len = strlen(cert_DN); - len2 = strlen(issuer_DN); - - /* issuer didn't have CA status, check for bad proxy extension */ - - if (len2 > len) return X509_V_ERR_INVALID_CA; - /* User not allowed to sign shortened DN */ - - if (strncmp(cert_DN, issuer_DN, len2) != 0) - return X509_V_ERR_INVALID_CA; - /* Proxy subject must begin with issuer. */ - - proxy_part_DN = &cert_DN[len2]; - /* Set pointer to end of DN base in cert_DN */ - - /* Remander of subject must be either "/CN=proxy" or - "/CN=limited proxy" (or /CN=XYZ for New style GSI) */ - - /* First attempt at support for Old and New style GSI - proxies: /CN=anything is ok for now. */ - if (strncmp(proxy_part_DN, "/CN=", 4) != 0) - return X509_V_ERR_INVALID_CA; - } - } - - return X509_V_OK; /* this is also GRST_RET_OK, of course - by choice */ -} - -/// Example VerifyCallback routine - -/** - * - */ - -int GRSTx509VerifyCallback (int ok, X509_STORE_CTX *ctx) -{ - int errnum = X509_STORE_CTX_get_error(ctx); - int errdepth = X509_STORE_CTX_get_error_depth(ctx); - int first_non_ca; - -#ifndef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION -#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 -#endif - - if (errnum == X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) - { - if (GRSTx509KnownCriticalExts(X509_STORE_CTX_get_current_cert(ctx)) - == GRST_RET_OK) - { - ok = TRUE; - errnum = X509_V_OK; - X509_STORE_CTX_set_error(ctx, errnum); - } - } - else if ((errdepth == 0) && - (errnum == X509_V_OK) && - (GRSTx509CheckChain(&first_non_ca, ctx) != X509_V_OK)) ok = FALSE; - - - return ok; - -// check this - -// if (ok) return GRST_RET_OK; -// else return GRST_RET_FAILED; -} - -/// Get the VOMS attributes in the extensions to the given cert -/* - * Puts any VOMS credentials found into the Compact Creds string array - * starting at *creds. Always returns GRST_RET_OK. - */ - -int GRSTx509GetVomsCreds(int *lastcred, int maxcreds, size_t credlen, - char *creds, X509 *cert, STACK_OF(X509) *certstack, - char *vomsdir) -{ -#ifndef GRST_VOMS_SUPPORT - return GRST_RET_OK; -} -#else - -/* - int j; - unsigned int siglen=-1, datalength=-1, dataoffset = -1; - char s[80]; - unsigned char *charstr, *p, *time1 = NULL, *time2 = NULL, *vo = NULL, - *uri = NULL, *user = NULL, *group = "NULL", *role = "NULL", - *cap = "NULL", *server = NULL, *ucuser, *signature = NULL, - *data = NULL, *datalen = NULL; - X509_EXTENSION *ex; - ASN1_STRING *asn1str; - time_t now, time1_time = 0, time2_time = 0, - uctime1_time, uctime2_time; -*/ - - - struct vomsdata *vd; - int i, j, vomserror; - - vd = VOMS_Init(NULL, NULL); - - if (VOMS_Retrieve(cert, certstack, RECURSE_CHAIN, vd, &vomserror) && - (vd->data != NULL)) - { - for (i = 0; vd->data[i] != NULL; ++i) - { - if (vd->data[i]->fqan != NULL) - for (j = 0; vd->data[i]->fqan[j] != NULL; ++j) - { - if (*lastcred >= maxcreds - 1) - { - VOMS_Destroy(vd); - return GRST_RET_OK; - } - - ++(*lastcred); - - snprintf(&creds[*lastcred * (credlen + 1)], - credlen+1, - "VOMS %010lu %010lu 0 %s", - GRSTasn1TimeToTimeT(vd->data[i]->date1), - GRSTasn1TimeToTimeT(vd->data[i]->date2), - vd->data[i]->fqan[j]); - } - } - } - else - { - FILE *fp = fopen("/tmp/getvoms.log", "w"); - fprintf(fp, "%d\n", vomserror); - fclose(fp); - } - - VOMS_Destroy(vd); - return GRST_RET_OK; -} - -#if 0 - - time(&now); - - uctime1_time = - GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(usercert))); - uctime2_time = - GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(usercert))); - ucuser = - X509_NAME_oneline(X509_get_subject_name(usercert), NULL, 0); - - for (i = 0; i < X509_get_ext_count(cert); ++i) - { - ex = X509_get_ext(cert, i); - - OBJ_obj2txt(s, sizeof(s), X509_EXTENSION_get_object(ex), 1); - - if (strcmp(s, GRST_VOMS_OID) == 0) /* a VOMS extension */ - { - asn1str = X509_EXTENSION_get_data(ex); - charstr = (char *) malloc(ASN1_STRING_length(asn1str) + 1); - memcpy(charstr, ASN1_STRING_data(asn1str), - ASN1_STRING_length(asn1str)); - charstr[ASN1_STRING_length(asn1str)] = '\0'; - - siglen = -1; - - if ((sscanf(charstr, "SIGLEN:%u", &siglen) != 1) || - (siglen == -1) || - ((p = index(charstr, '\n')) == NULL)) - { - free(charstr); - continue; - } - - ++p; - - if (strncmp(p, "SIGNATURE:", sizeof("SIGNATURE:") - 1) != 0) - { - free(charstr); - continue; - } - - signature = &p[sizeof("SIGNATURE:") - 1]; - - p = &p[siglen + sizeof("SIGNATURE:") - 1]; - data = p; - - /* nasty pointer arithmetic! */ - dataoffset = (unsigned int) ((long) data - (long) charstr); - datalength = (unsigned int) - (ASN1_STRING_length(asn1str) - dataoffset); - - if (datalength <= 0) - { - free(charstr); - continue; - } - - while (1) - { - if (strncmp(p, "USER:", sizeof("USER:") - 1) == 0) - { - p = &p[sizeof("USER:") - 1]; - while ((*p != '\n') && (*p != '\0') && (*p <= ' ')) ++p; - user = p; - p = index(p, '\n'); - if (p == NULL) break; - *p = '\0'; - ++p; - } - else if (strncmp(p, "TIME1:", sizeof("TIME1:") - 1) == 0) - { - p = &p[sizeof("TIME1:") - 1]; - while ((*p != '\n') && (*p != '\0') && (*p <= ' ')) ++p; - time1 = p; - p = index(p, '\n'); - if (p != NULL) *p = '\0'; - - time1_time = GRSTasn1TimeToTimeT(time1); - if (time1_time < uctime1_time) time1_time = uctime1_time; - if (p == NULL) break; - ++p; - } - else if (strncmp(p, "TIME2:", sizeof("TIME2:") - 1) == 0) - { - p = &p[sizeof("TIME2:") - 1]; - while ((*p != '\n') && (*p != '\0') && (*p <= ' ')) ++p; - time2 = p; - p = index(p, '\n'); - if (p != NULL) *p = '\0'; - - time2_time = GRSTasn1TimeToTimeT(time2); - if (time2_time > uctime2_time) time2_time = uctime2_time; - if (p == NULL) break; - ++p; - } - else if (strncmp(p, "VO:", sizeof("VO:") - 1) == 0) - { - p = &p[sizeof("VO:") - 1]; - while ((*p != '\n') && (*p != '\0') && (*p <= ' ')) ++p; - vo = p; - - p = index(p, '\n'); - if (p == NULL) break; - *p = '\0'; - ++p; - } - else if (strncmp(p, "SERVER:", sizeof("SERVER:") - 1) == 0) - { - p = &p[sizeof("SERVER:") - 1]; - while ((*p != '\n') && (*p != '\0') && (*p <= ' ')) ++p; - server = p; - - p = index(p, '\n'); - if (p == NULL) break; - *p = '\0'; - ++p; - } - else if (strncmp(p, "DATALEN:", sizeof("DATALEN:") - 1) == 0) - { - p = &p[sizeof("DATALEN:") - 1]; - while ((*p != '\n') && (*p != '\0') && (*p <= ' ')) ++p; - datalen = p; - p = index(p, '\n'); - if (p == NULL) break; - *p = '\0'; - ++p; - break; - } - else /* not something we use */ - { - p = index(p, '\n'); - if (p == NULL) break; - *p = '\0'; - ++p; - } - } -/* - if ((now >= time1_time) && - (now <= time2_time) && - (signature != NULL) && - (data != NULL) && - (siglen > 0) && - (user != NULL) && - (ucuser != NULL) && - (strcmp(user, ucuser) == 0) && - (GRSTx509CheckVomsSig(signature, siglen, - &((ASN1_STRING_data(asn1str))[dataoffset]), - datalength, vomsdir, vo, - server) == GRST_RET_OK)) - while (1) -*/ - { - if (strncmp(p, "GROUP:", sizeof("GROUP:") - 1) == 0) - { - p = &p[sizeof("GROUP:") - 1]; - while ((*p != '\n') && (*p != '\0') && (*p <= ' ')) ++p; - group = p; - role = "NULL"; - cap = "NULL"; - - p = index(p, '\n'); - if (p == NULL) break; - *p = '\0'; - ++p; - } - else if (strncmp(p, "ROLE:", sizeof("ROLE:") - 1) == 0) - { - p = &p[sizeof("ROLE:") - 1]; - while ((*p != '\n') && (*p != '\0') && (*p <= ' ')) ++p; - role = p; - - p = index(p, '\n'); - if (p == NULL) break; - *p = '\0'; - ++p; - } - else if (strncmp(p, "CAP:", sizeof("CAP:") - 1) == 0) - { - p = &p[sizeof("CAP:") - 1]; - while ((*p != '\n') && (*p != '\0') && (*p <= ' ')) ++p; - cap = p; - - p = index(p, '\n'); - if (p != NULL) *p = '\0'; - - if (*lastcred < maxcreds - 1) - { - ++(*lastcred); - - if ((strcmp(role, "NULL") == 0) && - (strcmp(cap , "NULL") == 0)) - snprintf(&creds[*lastcred * (credlen + 1)], credlen+1, - "VOMS %010lu %010lu 0 /%s%s", - time1_time, time2_time, vo, group); - else if ((strcmp(role, "NULL") != 0) && - (strcmp(cap , "NULL") == 0)) - snprintf(&creds[*lastcred * (credlen + 1)], credlen+1, - "VOMS %010lu %010lu 0 /%s%s/Role=%s", - time1_time, time2_time, vo, group, role); - else if ((strcmp(role, "NULL") == 0) && - (strcmp(cap , "NULL") != 0)) - snprintf(&creds[*lastcred * (credlen + 1)], credlen+1, - "VOMS %010lu %010lu 0 /%s%s/Capability=%s", - time1_time, time2_time, vo, group, cap); - else - snprintf(&creds[*lastcred * (credlen + 1)], credlen+1, - "VOMS %010lu %010lu 0 /%s%s/Role=%s/Capability=%s", - time1_time, time2_time, vo, group, role, cap); - } - - if (p == NULL) break; - ++p; - } - else /* not something we use */ - { - p = index(p, '\n'); - if (p == NULL) break; - *p = '\0'; - ++p; - } - } - - free(charstr); - } - } - - return GRST_RET_OK; -} -#endif - -#endif - -/// Turn a Compact Cred line into a GRSTgaclCred object -/** - * Returns pointer to created GRSTgaclCred or NULL or failure. - */ - -GRSTgaclCred *GRSTx509CompactToCred(char *grst_cred) -{ - int delegation; - char *p; - time_t now, notbefore, notafter; - GRSTgaclCred *cred = NULL; - - time(&now); - - if (grst_cred == NULL) return NULL; /* just in case */ - - if (strncmp(grst_cred, "X509USER ", 9) == 0) - { - if ((sscanf(grst_cred, "X509USER %lu %lu %d", - ¬before, ¬after, &delegation) == 3) - && (now >= notbefore) - && (now <= notafter) - && (p = index(grst_cred, ' ')) - && (p = index(++p, ' ')) - && (p = index(++p, ' ')) - && (p = index(++p, ' '))) - { - cred = GRSTgaclCredNew("person"); - GRSTgaclCredSetDelegation(cred, delegation); - GRSTgaclCredAddValue(cred, "dn", &p[1]); - } - - return cred; - } - - if (strncmp(grst_cred, "VOMS ", 5) == 0) - { - if ((sscanf(grst_cred, "VOMS %lu %lu", - ¬before, ¬after, &delegation) == 3) - && (now >= notbefore) - && (now <= notafter) - && (p = index(grst_cred, ' ')) - && (p = index(++p, ' ')) - && (p = index(++p, ' ')) - && (p = index(++p, ' '))) - { - /* include /VO/group/subgroup/Role=role/Capability=cap */ - - if (*p != '/') return NULL; /* must begin with / */ - - cred = GRSTgaclCredNew("voms"); - GRSTgaclCredSetDelegation(cred, delegation); - GRSTgaclCredAddValue(cred, "fqan", p); - } - - return cred; - } - - return NULL; /* dont recognise this credential type */ -} - -/// Get the credentials in an X509 cert/GSI proxy, including any VOMS -/** - * Credentials are placed in Compact Creds string array at *creds. - * - * Function returns GRST_RET_OK on success, or GRST_RET_FAILED if - * some inconsistency found in certificate. - */ - -int GRSTx509CompactCreds(int *lastcred, int maxcreds, size_t credlen, - char *creds, STACK_OF(X509) *certstack, char *vomsdir) -{ - int i, j, delegation = 0; - char credtemp[credlen+1]; - X509 *cert, *usercert = NULL, *gsiproxycert = NULL; - - *lastcred = -1; - - for (i = sk_X509_num(certstack) - 1; i >= 0; --i) - { - cert = sk_X509_value(certstack, i); - - if (usercert != NULL) - { /* found a (GSI proxy) cert after the user cert */ - gsiproxycert = cert; - ++delegation; - } - - if ((usercert == NULL) && - (i < sk_X509_num(certstack) - 1) && - (GRSTx509IsCA(cert) != GRST_RET_OK)) usercert = cert; - /* found the 1st non-CA cert */ - } - - if ((usercert == NULL) /* if no usercert ("EEC"), we're not interested */ - || - (snprintf(credtemp, credlen+1, "X509USER %010lu %010lu %d %s", - GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(usercert))), - GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(usercert))), - delegation, - X509_NAME_oneline(X509_get_subject_name(usercert), NULL, 0)) >= credlen+1) - || - (*lastcred >= maxcreds-1)) - { - *lastcred = -1; /* just in case the caller looks at it */ - return GRST_RET_FAILED; /* tell caller that things didn't work out */ - } - - ++(*lastcred); - strcpy(&creds[*lastcred * (credlen + 1)], credtemp); - - if ((gsiproxycert != NULL) - && - (snprintf(credtemp, credlen+1, "GSIPROXY %010lu %010lu %d %s", - GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notBefore(gsiproxycert))), - GRSTasn1TimeToTimeT(ASN1_STRING_data(X509_get_notAfter(gsiproxycert))), - delegation, - X509_NAME_oneline(X509_get_subject_name(gsiproxycert), NULL, 0)) < credlen+1) - && - (*lastcred < maxcreds-1)) - { - ++(*lastcred); - strcpy(&creds[*lastcred * (credlen + 1)], credtemp); - - GRSTx509GetVomsCreds(lastcred, maxcreds, credlen, creds, - gsiproxycert, certstack, vomsdir); - } - - return GRST_RET_OK; -} - -/// Find proxy file name of the current user -/** - * Return a string with the proxy file name or NULL if not present. - * This function does not check if the proxy has expired. - */ - -char *GRSTx509FindProxyFileName(void) -{ - char *p; - - p = getenv("X509_USER_PROXY"); - - if (p != NULL) return strdup(p); - - p = malloc(sizeof("/tmp/x509up_uXYYYXXXYYY")); - - sprintf(p, "/tmp/x509up_u%d", getuid()); - - return p; -} - -static void mpcerror(FILE *debugfp, char *msg) -{ - if (debugfp != NULL) - { - fputs(msg, debugfp); - ERR_print_errors_fp(debugfp); - } -} - -/// Make a GSI Proxy chain from a request, certificate and private key -/** - * The proxy chain is returned in *proxychain. If debugfp is non-NULL, - * errors are output to that file pointer. The proxy will expired in - * the given number of minutes starting from the current time. - */ - -int GRSTx509MakeProxyCert(char **proxychain, FILE *debugfp, - char *reqtxt, char *cert, char *key, int minutes) -{ - char *ptr, *certchain; - int i, subjAltName_pos, ncerts; - long serial = 1, ptrlen; - EVP_PKEY *pkey, *CApkey; - const EVP_MD *digest; - X509 *certs[GRST_MAX_CHAIN_LEN]; - X509_REQ *req; - X509_NAME *name, *CAsubject, *newsubject; - X509_NAME_ENTRY *ent; - X509V3_CTX ctx; - X509_EXTENSION *subjAltName; - STACK_OF (X509_EXTENSION) * req_exts; - FILE *fp; - BIO *reqmem, *certmem; - - /* read in the request */ - reqmem = BIO_new(BIO_s_mem()); - BIO_puts(reqmem, reqtxt); - - if (!(req = PEM_read_bio_X509_REQ(reqmem, NULL, NULL, NULL))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error reading request from BIO memory\n"); - BIO_free(reqmem); - return GRST_RET_FAILED; - } - - BIO_free(reqmem); - - /* verify signature on the request */ - if (!(pkey = X509_REQ_get_pubkey (req))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error getting public key from request\n"); - return GRST_RET_FAILED; - } - - if (X509_REQ_verify(req, pkey) != 1) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error verifying signature on certificate\n"); - return GRST_RET_FAILED; - } - - /* read in the signing certificate */ - if (!(fp = fopen(cert, "r"))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error opening signing certificate file\n"); - return GRST_RET_FAILED; - } - - for (ncerts = 1; ncerts < GRST_MAX_CHAIN_LEN; ++ncerts) - if (!(certs[ncerts] = PEM_read_X509(fp, NULL, NULL, NULL))) break; - - if (ncerts == 1) /* zeroth cert with be new proxy cert */ - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error reading signing certificate file\n"); - return GRST_RET_FAILED; - } - - fclose(fp); - - CAsubject = X509_get_subject_name(certs[1]); - - /* read in the CA private key */ - if (!(fp = fopen(key, "r"))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error reading signing private key file\n"); - return GRST_RET_FAILED; - } - - if (!(CApkey = PEM_read_PrivateKey (fp, NULL, NULL, NULL))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error reading signing private key in file\n"); - return GRST_RET_FAILED; - } - - fclose(fp); - - /* get subject name */ - if (!(name = X509_REQ_get_subject_name (req))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error getting subject name from request\n"); - return GRST_RET_FAILED; - } - - /* create new certificate */ - if (!(certs[0] = X509_new ())) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error creating X509 object\n"); - return GRST_RET_FAILED; - } - - /* set version number for the certificate (X509v3) and the serial number - need 3 = v4 for GSI proxy?? */ - if (X509_set_version (certs[0], 3L) != 1) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error setting certificate version\n"); - return GRST_RET_FAILED; - } - - ASN1_INTEGER_set (X509_get_serialNumber (certs[0]), serial++); - - if (!(name = X509_get_subject_name(certs[1]))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error getting subject name from CA certificate\n"); - return GRST_RET_FAILED; - } - - if (X509_set_issuer_name (certs[0], name) != 1) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error setting issuer name of certificate\n"); - return GRST_RET_FAILED; - } - - /* set issuer and subject name of the cert from the req and the CA */ - ent = X509_NAME_ENTRY_create_by_NID(NULL, OBJ_txt2nid("commonName"), - MBSTRING_ASC, "proxy", -1); - - newsubject = X509_NAME_dup(CAsubject); - - X509_NAME_add_entry(newsubject, ent, -1, 0); - - if (X509_set_subject_name(certs[0], newsubject) != 1) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error setting subject name of certificate\n"); - return GRST_RET_FAILED; - } - - /* set public key in the certificate */ - if (X509_set_pubkey(certs[0], pkey) != 1) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error setting public key of the certificate\n"); - return GRST_RET_FAILED; - } - -// need to set validity within limits of earlier certificates in the chain - - /* set duration for the certificate */ - if (!(X509_gmtime_adj (X509_get_notBefore(certs[0]), 0))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error setting beginning time of the certificate\n"); - return GRST_RET_FAILED; - } - - if (!(X509_gmtime_adj (X509_get_notAfter(certs[0]), 60 * minutes))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error setting ending time of the certificate\n"); - return GRST_RET_FAILED; - } - - /* sign the certificate with the signing private key */ - if (EVP_PKEY_type (CApkey->type) == EVP_PKEY_RSA) - digest = EVP_md5(); - else - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error checking signing private key for a valid digest\n"); - return GRST_RET_FAILED; - } - - if (!(X509_sign (certs[0], CApkey, digest))) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error signing certificate\n"); - return GRST_RET_FAILED; - } - - /* store the completed certificate chain */ - - certchain = strdup(""); - - for (i=0; i < ncerts; ++i) - { - certmem = BIO_new(BIO_s_mem()); - - if (PEM_write_bio_X509(certmem, certs[i]) != 1) - { - mpcerror(debugfp, - "GRSTx509MakeProxyCert(): error writing certificate to memory BIO\n"); - return GRST_RET_FAILED; - } - - ptrlen = BIO_get_mem_data(certmem, &ptr); - - certchain = realloc(certchain, strlen(certchain) + ptrlen + 1); - - strncat(certchain, ptr, ptrlen); - - BIO_free(certmem); - } - - *proxychain = certchain; - - return GRST_RET_OK; -} - -/// Find a proxy file in the proxy cache -/** - * Returns the full path and file name of proxy file associated - * with given delegation ID and user DN. - */ - -char *GRSTx509CachedProxyFind(char *proxydir, char *delegation_id, - char *user_dn) -/* - Return a pointer to a malloc'd string with the full path of the - proxy file corresponding to the given delegation_id, or NULL - if not found. -*/ -{ - int ret, len; - char *filename = NULL, *line, *p, *proxyfile = NULL; - DIR *proxyDIR; - FILE *fp; - struct dirent *ent; - struct stat entstat; - - if ((proxyDIR = opendir(proxydir)) == NULL) return NULL; - - len = strlen(delegation_id); - if (strlen(user_dn) > len) len = strlen(user_dn); - - if ((line = malloc(len + 2)) == NULL) return NULL; - - while ((ent = readdir(proxyDIR)) != NULL) - { - if (ent->d_name[0] != '.') /* private keys begin with . */ - { - if (asprintf(&filename, "%s/%s", proxydir, ent->d_name) == -1) - break; - if ((stat(filename, &entstat) != 0) - || !S_ISREG(entstat.st_mode)) - { - free(filename); - continue; - } - - fp = fopen(filename, "r"); - if (fp != NULL) - { - if (fgets(line, len + 2, fp) != NULL) - { - p = index(line, '\n'); - - if (p != NULL) - { - *p = '\0'; - if (strcmp(line, delegation_id) == 0) - { - if (fgets(line, len + 2, fp) != NULL) - { - p = index(line, '\n'); - - if (p != NULL) - { - *p = '\0'; - - if (strcmp(line, user_dn) == 0) - { - proxyfile = filename; - fclose(fp); - break; - } - } - } - } - } - } - - fclose(fp); - } - - free(filename); - } - } - - closedir(proxyDIR); - free(line); - - return proxyfile; -} - -/// Find a temporary proxy private key file in the proxy cache -/** - * Returns the full path and file name of the private key file associated - * with given delegation ID and user DN. - */ - -char *GRSTx509CachedProxyKeyFind(char *proxydir, char *delegation_id, - char *user_dn) -/* - Return a pointer to a malloc'd string with the full path of the - private proxy key corresponding to the given delegation_id, or NULL - if not found. -*/ -{ - int ret, len; - char *filename = NULL, *line, *p, *keyfile = NULL; - DIR *proxyDIR; - FILE *fp; - struct dirent *ent; - struct stat entstat; - - if ((proxyDIR = opendir(proxydir)) == NULL) return NULL; - - len = strlen(delegation_id); - if (strlen(user_dn) > len) len = strlen(user_dn); - - if ((line = malloc(len + 2)) == NULL) return NULL; - - while ((ent = readdir(proxyDIR)) != NULL) - { - if (ent->d_name[0] == '.') /* private keys begin with . */ - { - if (asprintf(&filename, "%s/%s", proxydir, ent->d_name) == -1) - break; - if ((stat(filename, &entstat) != 0) - || !S_ISREG(entstat.st_mode)) - { - free(filename); - continue; - } - - fp = fopen(filename, "r"); - if (fp != NULL) - { - if (fgets(line, len + 2, fp) != NULL) - { - p = index(line, '\n'); - - if (p != NULL) - { - *p = '\0'; - if (strcmp(line, delegation_id) == 0) - { - if (fgets(line, len + 2, fp) != NULL) - { - p = index(line, '\n'); - - if (p != NULL) - { - *p = '\0'; - - if (strcmp(line, user_dn) == 0) - { - keyfile = filename; - fclose(fp); - break; - } - } - } - } - } - } - - fclose(fp); - } - - free(filename); - } - } - - closedir(proxyDIR); - free(line); - - return keyfile; -} - -/// Make and store a X.509 request for a GSI proxy -/** - * Returns GRST_RET_OK on success, non-zero otherwise. Request string - * is PEM encoded, and the key is stored in proxydir as temporary file - * with a filename like .XXXXXX - */ - -int GRSTx509MakeProxyRequest(char **reqtxt, char *proxydir, - char *delegation_id, char *user_dn) -{ - int i, fd; - char *docroot, *reqfile, *prvkeyfile, *ptr; - size_t ptrlen; - FILE *fp; - RSA *keypair; - X509_NAME *subject; - X509_NAME_ENTRY *ent; - EVP_PKEY *pkey; - X509_REQ *certreq; - BIO *reqmem; - const EVP_MD *digest; - struct stat statbuf; - - if ((keypair = RSA_generate_key(GRST_KEYSIZE, 3, NULL, NULL)) == NULL) - return 1; - asprintf(&prvkeyfile, "%s/.XXXXXX", proxydir); - - fd = mkstemp(prvkeyfile); - - if ((fp = fdopen(fd, "w")) == NULL) return 1; - - fprintf(fp, "%s\n%s\n", delegation_id, user_dn); - - if (!PEM_write_RSAPrivateKey(fp, keypair, NULL, NULL, 0, NULL, NULL)) - return 1; - - if (fclose(fp) != 0) return 1; - - /* now create the certificate request */ - - certreq = X509_REQ_new(); - if (certreq == NULL) return 1; - - OpenSSL_add_all_algorithms(); - - pkey = EVP_PKEY_new(); - EVP_PKEY_assign_RSA(pkey, keypair); - - X509_REQ_set_pubkey(certreq, pkey); - - subject = X509_NAME_new(); - ent = X509_NAME_ENTRY_create_by_NID(NULL, OBJ_txt2nid("organizationName"), - MBSTRING_ASC, "Dummy", -1); - X509_NAME_add_entry (subject, ent, -1, 0); - X509_REQ_set_subject_name (certreq, subject); - - digest = EVP_md5(); - X509_REQ_sign(certreq, pkey, digest); - - reqmem = BIO_new(BIO_s_mem()); - PEM_write_bio_X509_REQ(reqmem, certreq); - ptrlen = BIO_get_mem_data(reqmem, &ptr); - - *reqtxt = malloc(ptrlen + 1); - memcpy(*reqtxt, ptr, ptrlen); - (*reqtxt)[ptrlen] = '\0'; - - BIO_free(reqmem); - - X509_REQ_free(certreq); - - return 0; -} - -/// Store a GSI proxy chain in the proxy cache, along with the private key -/** - * Returns GRST_RET_OK on success, non-zero otherwise. The existing - * private key with the same delegation ID and user DN is appended to - * make a valid proxy file, and the temporary private key file deleted. - */ - -int GRSTx509CacheProxy(char *proxydir, char *delegation_id, - char *user_dn, char *proxychain) -{ - int fd, c, len = 0, i; - char *cert, *upcertfile, *prvkeyfile, *p; - FILE *ifp, *ofp; - - prvkeyfile = GRSTx509CachedProxyKeyFind(proxydir, delegation_id, user_dn); - - if (prvkeyfile == NULL) - { - free(proxydir); - return GRST_RET_FAILED; - } - - if ((ifp = fopen(prvkeyfile, "r")) == NULL) - { - free(prvkeyfile); - free(proxydir); - return GRST_RET_FAILED; - } - - if (asprintf(&upcertfile, "%s/XXXXXX", proxydir) == -1) - return GRST_RET_FAILED; - - if ((fd = mkstemp(upcertfile)) == -1) - { - fclose(ifp); - free(prvkeyfile); - free(upcertfile); - return GRST_RET_FAILED; - } - - if ((ofp = fdopen(fd, "w")) == NULL) - { - close(fd); - fclose(ifp); - free(prvkeyfile); - free(upcertfile); - return GRST_RET_FAILED; - } - - fprintf(ofp, "%s\n%s\n", delegation_id, user_dn); - - fputs(proxychain, ofp); /* write out certificates */ - - while ((c = fgetc(ifp)) != EOF) fputc(c, ofp); /* append proxy private key */ - - if (fclose(ifp) != 0) return GRST_RET_FAILED; - if (fclose(ofp) != 0) return GRST_RET_FAILED; - - unlink(prvkeyfile); - - free(prvkeyfile); - free(upcertfile); - -/* should also check validity of proxy cert to avoid suprises? */ - - return GRST_RET_OK; -} diff --git a/org.gridsite.core/src/htcp b/org.gridsite.core/src/htcp deleted file mode 100644 index ac0153b23a52348015c9bedbcc3153157cb93075..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 29747 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 -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/* deal with older versions of libcurl and curl.h */ - -#ifndef CURLOPT_WRITEDATA -#define CURLOPT_WRITEDATA CURLOPT_FILE -#endif - -#ifndef CURLOPT_READDATA -#define CURLOPT_READDATA CURLOPT_FILE -#endif - -#ifndef CURLE_HTTP_RETURNED_ERROR -#define CURLE_HTTP_RETURNED_ERROR CURLE_HTTP_NOT_FOUND -#endif - -#define HTCP_GET 1 -#define HTCP_PUT 2 -#define HTCP_DELETE 3 -#define HTCP_LIST 4 -#define HTCP_LONGLIST 5 -#define HTCP_MKDIR 6 - -struct grst_stream_data { char *source; - char *destination; - int ishttps; - int method; - FILE *fp; - char *cert; - char *key; - char *capath; - char *useragent; - char *errorbuf; - int noverify; - int anonymous; - long long downgrade; - int verbose; } ; - -struct grst_index_blob { char *text; - size_t used; - size_t allocated; } ; - -struct grst_dir_list { char *filename; - size_t length; - int length_set; - time_t modified; - int modified_set; } ; - -struct grst_header_data { int retcode; - char *location; - char *gridauthonetime; - size_t length; - int length_set; - time_t modified; - int modified_set; - struct grst_stream_data *common_data; } ; - -size_t headers_callback(void *ptr, size_t size, size_t nmemb, void *p) -/* Find the values of the return code, Content-Length, Last-Modified - and Location headers */ -{ - float f; - char *s, *q; - size_t realsize; - struct tm modified_tm; - struct grst_header_data *header_data; - - header_data = (struct grst_header_data *) p; - realsize = size * nmemb; - s = malloc(realsize + 1); - memcpy(s, ptr, realsize); - s[realsize] = '\0'; - - if (sscanf(s, "Content-Length: %d", &(header_data->length)) == 1) - header_data->length_set = 1; - else if (sscanf(s, "HTTP/%f %d ", &f, &(header_data->retcode)) == 2) ; - else if (strncmp(s, "Location: ", 10) == 0) - { - header_data->location = strdup(&s[10]); - - if (header_data->common_data->verbose > 0) - fprintf(stderr, "Received Location: %s\n", header_data->location); - } - else if (strncmp(s, "Set-Cookie: GRID_AUTH_ONETIME=", 30) == 0) - { - header_data->gridauthonetime = strdup(&s[12]); - q = index(header_data->gridauthonetime, ';'); - if (q != NULL) *q = '\0'; - - if (header_data->common_data->verbose > 0) - fprintf(stderr, "Received Grid Auth Cookie: %s\n", - header_data->gridauthonetime); - } - else if (strncmp(s, "Last-Modified: ", 15) == 0) - { - /* follow RFC 2616: first try RFC 822 (kosher), then RFC 850 and - asctime() formats too. Must be GMT whatever the format. */ - - if (strptime(&s[15], "%a, %d %b %Y %T GMT", &modified_tm) != NULL) - { - header_data->modified = mktime(&modified_tm); - header_data->modified_set = 1; - } - else if (strptime(&s[15], "%a, %d-%b-%y %T GMT", &modified_tm) != NULL) - { - header_data->modified = mktime(&modified_tm); - header_data->modified_set = 1; - } - else if (strptime(&s[15], "%a %b %d %T %Y", &modified_tm) != NULL) - { - header_data->modified = mktime(&modified_tm); - header_data->modified_set = 1; - } - } - - free(s); - return realsize; -} - -int set_std_opts(CURL *easyhandle, struct grst_stream_data *common_data) -{ - struct stat statbuf; - - curl_easy_setopt(easyhandle, CURLOPT_FOLLOWLOCATION, 0); - - if ((common_data->cert != NULL) && (common_data->key != NULL)) - { - curl_easy_setopt(easyhandle, CURLOPT_SSLENGINE, NULL); - curl_easy_setopt(easyhandle, CURLOPT_SSLCERTTYPE, "PEM"); - curl_easy_setopt(easyhandle, CURLOPT_SSLCERT, common_data->cert); - curl_easy_setopt(easyhandle, CURLOPT_SSLKEY, common_data->key); - } - else - { - curl_easy_setopt(easyhandle, CURLOPT_SSLENGINE, "RSA"); - curl_easy_setopt(easyhandle, CURLOPT_SSLCERTTYPE, "ENG"); - } - - if (common_data->capath != NULL) - { -#if (LIBCURL_VERSION_NUM >= 0x070908) - if ((stat(common_data->capath, &statbuf) == 0) && - S_ISDIR(statbuf.st_mode)) - curl_easy_setopt(easyhandle, CURLOPT_CAPATH, common_data->capath); - else -#endif - curl_easy_setopt(easyhandle, CURLOPT_CAINFO, common_data->capath); - } - - if (common_data->noverify) - curl_easy_setopt(easyhandle, CURLOPT_SSL_VERIFYHOST, 0); - else curl_easy_setopt(easyhandle, CURLOPT_SSL_VERIFYHOST, 2); - - return 1; -} - -int do_copies(char *sources[], char *destination, - struct grst_stream_data *common_data) -{ - char *p, *thisdestination; - int isrc, anyerror = 0, thiserror, isdirdest; - CURL *easyhandle; - struct stat statbuf; - struct grst_header_data header_data; - struct curl_slist *dgheader_slist = NULL, *nodgheader_slist = NULL; - - easyhandle = curl_easy_init(); - - if (common_data->downgrade >= (long long) 0) - { - asprintf(&p, "HTTP-Downgrade-Size: %lld", common_data->downgrade); - dgheader_slist = curl_slist_append(dgheader_slist, p); - free(p); - - nodgheader_slist = curl_slist_append(nodgheader_slist, - "HTTP-Downgrade-Size:"); - } - - curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, common_data->useragent); - if (common_data->verbose > 1) - curl_easy_setopt(easyhandle, CURLOPT_VERBOSE, 1); - - curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, headers_callback); - curl_easy_setopt(easyhandle, CURLOPT_WRITEHEADER, &header_data); - - set_std_opts(easyhandle, common_data); - - curl_easy_setopt(easyhandle, CURLOPT_ERRORBUFFER, common_data->errorbuf); - - if (destination[strlen(destination) - 1] != '/') - { - isdirdest = 0; - thisdestination = destination; - } - else isdirdest = 1; - - for (isrc=0; sources[isrc] != NULL; ++isrc) - { - if (isdirdest) - { - p = rindex(sources[isrc], '/'); - if (p == NULL) p = sources[isrc]; - else p++; - - asprintf(&thisdestination, "%s%s", destination, p); - } - - if (common_data->verbose > 0) - fprintf(stderr, "%s -> %s\n", sources[isrc], thisdestination); - - if (common_data->method == HTCP_GET) - { - common_data->fp = fopen(thisdestination, "w"); - if (common_data->fp == NULL) - { - fprintf(stderr,"... failed to open destination source file %s\n", - thisdestination); - anyerror = 99; - if (isdirdest) free(thisdestination); - continue; - } - - curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, common_data->fp); - curl_easy_setopt(easyhandle, CURLOPT_URL, sources[isrc]); - - if ((common_data->downgrade >= (long long) 0) && - (strncmp(sources[isrc], "https://", 8) == 0)) - { - if (common_data->verbose > 0) - fprintf(stderr, "Add HTTP-Downgrade-Size: %lld header\n", - common_data->downgrade); - - curl_easy_setopt(easyhandle,CURLOPT_HTTPHEADER,dgheader_slist); - } - else - curl_easy_setopt(easyhandle,CURLOPT_HTTPHEADER,nodgheader_slist); - } - else if (common_data->method == HTCP_PUT) - { - if (stat(sources[isrc], &statbuf) != 0) - { - fprintf(stderr, "... source file %s not found\n", sources[isrc]); - anyerror = 99; - if (isdirdest) free(thisdestination); - continue; - } - - common_data->fp = fopen(sources[isrc], "r"); - if (common_data->fp == NULL) - { - fprintf(stderr, "... failed to open source file %s\n", - sources[isrc]); - anyerror = 99; - if (isdirdest) free(thisdestination); - continue; - } - - curl_easy_setopt(easyhandle, CURLOPT_READDATA, common_data->fp); - curl_easy_setopt(easyhandle, CURLOPT_URL, thisdestination); - curl_easy_setopt(easyhandle, CURLOPT_INFILESIZE, statbuf.st_size); - curl_easy_setopt(easyhandle, CURLOPT_UPLOAD, 1); - - if (((long long) statbuf.st_size >= common_data->downgrade) && - (strncmp(thisdestination, "https://", 8) == 0)) - curl_easy_setopt(easyhandle,CURLOPT_HTTPHEADER,dgheader_slist); - else - curl_easy_setopt(easyhandle,CURLOPT_HTTPHEADER,nodgheader_slist); - } - - header_data.retcode = 0; - header_data.location = NULL; - header_data.gridauthonetime = NULL; - header_data.common_data = common_data; - thiserror = curl_easy_perform(easyhandle); - - fclose(common_data->fp); - - if ((common_data->downgrade >= (long long) 0) && - (thiserror == 0) && - (header_data.retcode == 302) && - (header_data.location != NULL) && - (strncmp(header_data.location, "http://", 7) == 0) && - (header_data.gridauthonetime != NULL)) - { - if (common_data->verbose > 0) - fprintf(stderr, "... Found (%d)\nHTTP-Downgrade to %s\n", - header_data.retcode, header_data.location); - - /* try again with new URL and all the previous CURL options */ - - if (common_data->method == HTCP_GET) - { - common_data->fp = fopen(thisdestination, "w"); - if (common_data->fp == NULL) - { - fprintf(stderr, "... failed to open destination source " - "file %s\n", thisdestination); - anyerror = 99; - if (isdirdest) free(thisdestination); - continue; - } - } - else if (common_data->method == HTCP_PUT) - { - common_data->fp = fopen(sources[isrc], "r"); - if (common_data->fp == NULL) - { - fprintf(stderr, "... failed to open source file %s\n", - sources[isrc]); - anyerror = 99; - if (isdirdest) free(thisdestination); - continue; - } - } - - header_data.retcode = 0; - curl_easy_setopt(easyhandle, CURLOPT_URL, header_data.location); - curl_easy_setopt(easyhandle, CURLOPT_HTTPHEADER, nodgheader_slist); - curl_easy_setopt(easyhandle, CURLOPT_COOKIE, - header_data.gridauthonetime); - thiserror = curl_easy_perform(easyhandle); - - fclose(common_data->fp); - } - - if ((thiserror != 0) || - (header_data.retcode < 200) || - (header_data.retcode >= 300)) - { - fprintf(stderr, "... curl error: %s (%d), HTTP error: %d\n", - common_data->errorbuf, thiserror, header_data.retcode); - - if (thiserror != 0) anyerror = thiserror; - else anyerror = header_data.retcode; - } - else if (common_data->verbose > 0) - fprintf(stderr, "... OK (%d)\n", header_data.retcode); - - if (isdirdest) free(thisdestination); - } - - curl_easy_cleanup(easyhandle); - - return anyerror; -} - -int do_deletes(char *sources[], struct grst_stream_data *common_data) -{ - int isrc, anyerror = 0, thiserror; - CURL *easyhandle; - struct grst_header_data header_data; - - header_data.common_data = common_data; - - easyhandle = curl_easy_init(); - - curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, common_data->useragent); - if (common_data->verbose > 1) - curl_easy_setopt(easyhandle, CURLOPT_VERBOSE, 1); - - curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, headers_callback); - curl_easy_setopt(easyhandle, CURLOPT_WRITEHEADER, &header_data); - - curl_easy_setopt(easyhandle, CURLOPT_ERRORBUFFER, common_data->errorbuf); - curl_easy_setopt(easyhandle, CURLOPT_CUSTOMREQUEST, "DELETE"); - curl_easy_setopt(easyhandle, CURLOPT_NOBODY, 1); - - set_std_opts(easyhandle, common_data); - - for (isrc=0; sources[isrc] != NULL; ++isrc) - { - if (common_data->verbose > 0) - fprintf(stderr, "Deleting %s\n", sources[isrc]); - - curl_easy_setopt(easyhandle, CURLOPT_URL, sources[isrc]); - - header_data.retcode = 0; - thiserror = curl_easy_perform(easyhandle); - - if ((thiserror != 0) || - (header_data.retcode < 200) || - (header_data.retcode >= 300)) - { - fprintf(stderr, "... curl error: %s (%d), HTTP error: %d\n", - common_data->errorbuf, thiserror, header_data.retcode); - - if (thiserror != 0) anyerror = thiserror; - else anyerror = header_data.retcode; - } - else if (common_data->verbose > 0) - fprintf(stderr, "... OK (%d)\n", header_data.retcode); - } - - curl_easy_cleanup(easyhandle); - - return anyerror; -} - -int do_mkdirs(char *sources[], struct grst_stream_data *common_data) -{ - int isrc, anyerror = 0, thiserror; - CURL *easyhandle; - struct grst_header_data header_data; - - header_data.common_data = common_data; - - easyhandle = curl_easy_init(); - - curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, common_data->useragent); - if (common_data->verbose > 1) - curl_easy_setopt(easyhandle, CURLOPT_VERBOSE, 1); - - curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, headers_callback); - curl_easy_setopt(easyhandle, CURLOPT_WRITEHEADER, &header_data); - - curl_easy_setopt(easyhandle, CURLOPT_ERRORBUFFER, common_data->errorbuf); - curl_easy_setopt(easyhandle, CURLOPT_CUSTOMREQUEST, "PUT"); - curl_easy_setopt(easyhandle, CURLOPT_NOBODY, 1); - - set_std_opts(easyhandle, common_data); - - for (isrc=0; sources[isrc] != NULL; ++isrc) - { - if (common_data->verbose > 0) - fprintf(stderr, "Make directory %s\n", sources[isrc]); - - curl_easy_setopt(easyhandle, CURLOPT_URL, sources[isrc]); - - header_data.retcode = 0; - thiserror = curl_easy_perform(easyhandle); - - if ((thiserror != 0) || - (header_data.retcode < 200) || - (header_data.retcode >= 300)) - { - fprintf(stderr, "... curl error: %s (%d), HTTP error: %d\n", - common_data->errorbuf, thiserror, header_data.retcode); - - if (thiserror != 0) anyerror = thiserror; - else anyerror = header_data.retcode; - } - else if (common_data->verbose > 0) - fprintf(stderr, "... OK (%d)\n", header_data.retcode); - } - - curl_easy_cleanup(easyhandle); - - return anyerror; -} - -size_t rawindex_callback(void *ptr, size_t size, size_t nmemb, void *data) -{ - if ( ((struct grst_index_blob *) data)->used + size * nmemb >= - ((struct grst_index_blob *) data)->allocated ) - { - ((struct grst_index_blob *) data)->allocated = - ((struct grst_index_blob *) data)->used + size * nmemb + 4096; - - ((struct grst_index_blob *) data)->text = - realloc( ((struct grst_index_blob *) data)->text, - ((struct grst_index_blob *) data)->allocated ); - } - - memcpy( &( ((struct grst_index_blob *) - data)->text[((struct grst_index_blob *) data)->used] ), - ptr, size * nmemb); - - ((struct grst_index_blob *) data)->used += size * nmemb; - - return size * nmemb; -} - -char *canonicalise(char *link, char *source) -{ - int i, j, srclen; - char *s; - - srclen = strlen(source); - - if ((strncmp(link, "https://", 8) == 0) || - (strncmp(link, "http://", 7) == 0)) - { - if (strncmp(link, source, srclen) != 0) return NULL; /* other site */ - - if (link[srclen] == '\0') return NULL; /* we dont self-link! */ - - for (i=0; link[srclen + i] != '\0'; ++i) - if (link[srclen + i] == '/') - { - if (link[srclen + i + 1] != '\0') return NULL; /* no subdirs */ - else return strdup(&link[srclen]); /* resolves to this dir */ - } - } - else if (link[0] != '/') /* relative link - need to check for subsubdirs */ - { - for (i=0; link[i] != '\0'; ++i) - if ((link[i] == '/') && (link[i+1] != '\0')) return NULL; - - s = strdup(link); - - for (i=0; s[i] != '\0'; ++i) - if (s[i] == '#') - { - s[i] = '\0'; - break; - } - - return s; - } - - /* absolute link on this server, starting / */ - - for (i=8; source[i] != '\0'; ++i) if (source[i] == '/') break; - - if (strncmp(link, &source[i], srclen - i) != 0) return NULL; - - for (j = srclen - i; link[j] != '\0'; ++j) - if ((link[j] == '/') && (link[j+1] != '\0')) return NULL; - - s = strdup(&link[srclen - i]); - - for (i=0; s[i] != '\0'; ++i) - if (s[i] == '#') - { - s[i] = '\0'; - break; - } - - if (s[0] == '\0') /* on second thoughts... */ - { - free(s); - return NULL; - } - - return s; -} - -int grst_dir_list_cmp(const void *a, const void *b) -{ - return strcmp( ((struct grst_dir_list *) a)->filename, - ((struct grst_dir_list *) b)->filename); -} - -struct grst_dir_list *index_to_dir_list(char *text, char *source) -{ - int taglevel = 0, wordnew = 1, i, namestart, used = 0, - allocated = 256; - char *p, *s; - struct grst_dir_list *list; - - list = (struct grst_dir_list *) - malloc(allocated * sizeof(struct grst_dir_list)); - - list[0].filename = NULL; - list[0].length = 0; - list[0].length_set = 0; - list[0].modified = 0; - list[0].modified_set = 0; - - for (p=text; *p != '\0'; ++p) - { - if (*p == '<') - { - ++taglevel; - - if ((taglevel == 1) && (list[used].filename != NULL)) - { - ++used; - if (used >= allocated) - { - allocated += 256; - list = (struct grst_dir_list *) - realloc((void *) list, - allocated * sizeof(struct grst_dir_list)); - } - - list[used].filename = NULL; - list[used].length = 0; - list[used].length_set = 0; - list[used].modified = 0; - list[used].modified_set = 0; - } - - wordnew = 1; - continue; - } - - if (*p == '>') - { - --taglevel; - wordnew = 1; - continue; - } - - if (isspace(*p)) - { - wordnew = 1; - continue; - } - - if ((wordnew) && (taglevel == 1)) - { - if (((*p == 'h') || (*p == 'H')) && - (strncasecmp(p, "href=", 5) == 0)) - { - if (p[5] == '"') { namestart = 6; - for (i=namestart; (p[i] != '\0') && - (p[i] != '"' ) && - (p[i] != '\n') && - (p[i] != '\t') && - (p[i] != '>' ) ; ++i) ; } - else { namestart = 5; - for (i=namestart; (p[i] != '\0') && - (p[i] != '"' ) && - (p[i] != ' ' ) && - (p[i] != '\n') && - (p[i] != '\t') && - (p[i] != ')' ) && - (p[i] != '>' ) ; ++i) ; } - if (i > namestart) - { - s = malloc(1 + i - namestart); - memcpy(s, &p[namestart], i - namestart); - s[i - namestart] = '\0'; - - list[used].filename = canonicalise(s, source); - free(s); - } - - p = &p[i-1]; /* -1 since continue results in ++i */ - continue; - } - - if (((*p == 'c') || (*p == 'C')) && - (strncasecmp(p, "content-length=", 15) == 0)) - { - list[used].length = 0; - list[used].length_set = 1; - - if (p[15] == '"') list[used].length = atoi(&p[16]); - else list[used].length = atoi(&p[15]); - - p = &p[15]; - continue; - } - - if (((*p == 'l') || (*p == 'L')) && - (strncasecmp(p, "last-modified=", 14) == 0)) - { - list[used].modified = 0; - list[used].modified_set = 1; - - if (p[14] == '"') list[used].modified = atoi(&p[15]); - else list[used].modified = atoi(&p[14]); - - p = &p[14]; - continue; - } - } - - wordnew = 0; - } - - qsort((void *) list, used, sizeof(struct grst_dir_list), grst_dir_list_cmp); - - return list; -} - -int do_listings(char *sources[], struct grst_stream_data *common_data, - int islonglist) -{ - int isrc, anyerror = 0, thiserror, i, isdir, ilast; - CURL *easyhandle; - const char *months[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", - "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; - char *s; - struct grst_index_blob rawindex; - struct grst_dir_list *list; - struct grst_header_data header_data; - struct tm modified_tm; - time_t now; - - time(&now); - - header_data.common_data = common_data; - - easyhandle = curl_easy_init(); - - curl_easy_setopt(easyhandle, CURLOPT_USERAGENT, common_data->useragent); - if (common_data->verbose > 1) - curl_easy_setopt(easyhandle, CURLOPT_VERBOSE, 1); - - curl_easy_setopt(easyhandle, CURLOPT_WRITEHEADER, &header_data); - curl_easy_setopt(easyhandle, CURLOPT_HEADERFUNCTION, headers_callback); - - curl_easy_setopt(easyhandle, CURLOPT_ERRORBUFFER, common_data->errorbuf); - - set_std_opts(easyhandle, common_data); - - for (isrc=0; sources[isrc] != NULL; ++isrc) - { - if (common_data->verbose > 0) - fprintf(stderr, "Listing %s\n", sources[isrc]); - - if (sources[1] != NULL) printf("\n%s:\n", sources[isrc]); - - curl_easy_setopt(easyhandle, CURLOPT_URL, sources[isrc]); - - if (sources[isrc][strlen(sources[isrc])-1] == '/') - { - isdir = 1; - curl_easy_setopt(easyhandle,CURLOPT_WRITEFUNCTION,rawindex_callback); - curl_easy_setopt(easyhandle,CURLOPT_WRITEDATA,(void *) &rawindex); - curl_easy_setopt(easyhandle,CURLOPT_NOBODY,0); - rawindex.text = NULL; - rawindex.used = 0; - rawindex.allocated = 0; - } - else - { - isdir = 0; - curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, NULL); - curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, NULL); - curl_easy_setopt(easyhandle, CURLOPT_NOBODY, 1); - } - - header_data.gridauthonetime = NULL; - header_data.length_set = 0; - header_data.modified_set = 0; - header_data.retcode = 0; - thiserror = curl_easy_perform(easyhandle); - - if ((thiserror != 0) || - (header_data.retcode < 200) || - (header_data.retcode >= 300)) - { - fprintf(stderr, "... curl error: %s (%d), HTTP error: %d\n", - common_data->errorbuf, thiserror, header_data.retcode); - - if (thiserror != 0) anyerror = thiserror; - else anyerror = header_data.retcode; - } - else if (isdir) - { - if (common_data->verbose > 0) - fprintf(stderr, "... OK (%d)\n", header_data.retcode); - - rawindex.text[rawindex.used] = '\0'; - - list = index_to_dir_list(rawindex.text, sources[isrc]); - ilast = -1; - - for (i=0; list[i].filename != NULL; ++i) - { - if (list[i].filename[0] == '.') continue; - - if (strncmp(list[i].filename, "mailto:", 7) == 0) continue; - - if ((ilast >= 0) && - (strcmp(list[i].filename, list[ilast].filename) == 0)) - continue; - ilast=i; - - if (islonglist) - { - if (!list[i].length_set || !list[i].modified_set) - { - curl_easy_setopt(easyhandle, CURLOPT_WRITEFUNCTION, - NULL); - curl_easy_setopt(easyhandle, CURLOPT_WRITEDATA, NULL); - curl_easy_setopt(easyhandle, CURLOPT_NOBODY, 1); - - asprintf(&s, "%s%s", sources[isrc], list[i].filename); - curl_easy_setopt(easyhandle, CURLOPT_URL, s); - - header_data.gridauthonetime = NULL; - header_data.length_set = 0; - header_data.modified_set = 0; - header_data.retcode = 0; - thiserror = curl_easy_perform(easyhandle); - free(s); - - if ((thiserror == 0) && - (header_data.retcode >= 200) && - (header_data.retcode <= 299)) - { - if (header_data.length_set) - { - list[i].length_set = 1; - list[i].length = header_data.length; - } - - if (header_data.modified_set) - { - list[i].modified_set = 1; - list[i].modified = header_data.modified; - } - } - } - - if (list[i].length_set) printf("%10ld ", list[i].length); - else fputs(" ? ", stdout); - - if (list[i].modified_set) - { - localtime_r(&(list[i].modified), &modified_tm); - - if (list[i].modified < now - 15552000) - printf("%s %2d %4d ", - months[modified_tm.tm_mon], - modified_tm.tm_mday, - modified_tm.tm_year + 1900); - else printf("%s %2d %02d:%02d ", - months[modified_tm.tm_mon], - modified_tm.tm_mday, - modified_tm.tm_hour, - modified_tm.tm_min); - } - else fputs(" ? ? ? ", stdout); - } - - puts(list[i].filename); - } - } - else - { - if (islonglist) - { - printf("%10ld ", header_data.length); - - localtime_r(&(header_data.modified), &modified_tm); - - if (header_data.modified < now - 15552000) - printf("%s %2d %4d ", - months[modified_tm.tm_mon], - modified_tm.tm_mday, - modified_tm.tm_year + 1900); - else printf("%s %2d %02d:%02d ", - months[modified_tm.tm_mon], - modified_tm.tm_mday, - modified_tm.tm_hour, - modified_tm.tm_min); - } - - puts(sources[isrc]); - } - } - - curl_easy_cleanup(easyhandle); - - return anyerror; -} - -#if (LIBCURL_VERSION_NUM < 0x070908) -char *make_tmp_ca_roots(char *dir) -/* libcurl before 7.9.8 doesnt support CURLOPT_CAPATH and the directory, - so we make a temporary file with the concatenated CA root certs: that - is, all the files in that directory which end in .0 */ -{ - int ofd, ifd, c; - size_t size; - char tmp_ca_roots[] = "/tmp/.ca-roots-XXXXXX", buffer[4096], *s; - DIR *rootsDIR; - struct dirent *root_ent; - - if ((rootsDIR = opendir(dir)) == NULL) return NULL; - - if ((ofd = mkstemp(tmp_ca_roots)) == -1) - { - closedir(rootsDIR); - return NULL; - } - - while ((root_ent = readdir(rootsDIR)) != NULL) - { - if ((root_ent->d_name[0] != '.') && - (strlen(root_ent->d_name) > 2) && - (strncmp(&(root_ent->d_name[strlen(root_ent->d_name)-2]), - ".0", 2) == 0)) - { - asprintf(&s, "%s/%s", dir, root_ent->d_name); - ifd = open(s, O_RDONLY); - free(s); - - if (ifd != -1) - { - while ((size = read(ifd, buffer, sizeof(buffer))) > 0) - write(ofd, buffer, size); - close(ifd); - } - } - } - - closedir(rootsDIR); - - if (close(ofd) == 0) return strdup(tmp_ca_roots); - - unlink(tmp_ca_roots); /* try to clean up */ - - return NULL; -} -#endif - -void printsyntax(char *argv0) -{ - char *p; - - p = rindex(argv0, '/'); - if (p != NULL) ++p; - else p = argv0; - - fprintf(stderr, "%s [options] Source-URL[s] [Destination URL]\n" - "%s is one of a set of clients to fetch files or directory listings\n" -"from remote servers using HTTP or HTTPS, or to put or delete files or\n" -"directories onto remote servers using HTTPS. htcp is similar to scp(1)\n" -"but uses HTTP/HTTPS rather than ssh as its transfer protocol.\n" -"See the htcp(1) or http://www.gridsite.org/ for details.\n" -"(Version: %s)\n", p, p, VERSION); -} - -int main(int argc, char *argv[]) -{ - char **sources, *destination = NULL, *executable, *p; - int c, i, option_index, anyerror; - struct stat statbuf; - struct grst_stream_data common_data; - struct passwd *userpasswd; - struct option long_options[] = { {"verbose", 0, 0, 'v'}, - {"cert", 1, 0, 0}, - {"key", 1, 0, 0}, - {"capath", 1, 0, 0}, - {"delete", 0, 0, 0}, - {"list", 0, 0, 0}, - {"long-list", 0, 0, 0}, - {"mkdir", 0, 0, 0}, - {"no-verify", 0, 0, 0}, - {"anon", 0, 0, 0}, - {"downgrade-size", 1, 0, 0}, -// {"streams", 1, 0, 0}, -// {"blocksize", 1, 0, 0}, -// {"recursive", 0, 0, 0}, - {0, 0, 0, 0} }; - -#if (LIBCURL_VERSION_NUM < 0x070908) - char *tmp_ca_roots = NULL; -#endif - - if (argc == 1) - { - printsyntax(argv[0]); - return 0; - } - - common_data.cert = NULL; - common_data.key = NULL; - common_data.capath = NULL; - common_data.method = 0; - common_data.errorbuf = malloc(CURL_ERROR_SIZE); - asprintf(&(common_data.useragent), - "htcp/%s (http://www.gridsite.org/)", VERSION); - common_data.verbose = 0; - common_data.noverify = 0; - common_data.anonymous = 0; - common_data.downgrade = (long long) -1; - - while (1) - { - option_index = 0; - - c = getopt_long(argc, argv, "v", long_options, &option_index); - - if (c == -1) break; - else if (c == 0) - { - if (option_index == 1) common_data.cert = optarg; - else if (option_index == 2) common_data.key = optarg; - else if (option_index == 3) common_data.capath = optarg; - else if (option_index == 4) common_data.method = HTCP_DELETE; - else if (option_index == 5) common_data.method = HTCP_LIST; - else if (option_index == 6) common_data.method = HTCP_LONGLIST; - else if (option_index == 7) common_data.method = HTCP_MKDIR; - else if (option_index == 8) common_data.noverify = 1; - else if (option_index == 9) common_data.anonymous = 1; - else if (option_index ==10) common_data.downgrade = atoll(optarg); - } - else if (c == 'v') ++(common_data.verbose); - } - - if (common_data.verbose > 0) - { - p = rindex(argv[0], '/'); - if (p != NULL) ++p; - else p = argv[0]; - fprintf(stderr, "%s version %s\n", p, VERSION); - } - - if (common_data.anonymous) /* prevent any use of user certs */ - { - common_data.cert = NULL; - common_data.key = NULL; - } - else if ((common_data.cert == NULL) && (common_data.key != NULL)) - common_data.cert = common_data.key; - else if ((common_data.cert != NULL) && (common_data.key == NULL)) - common_data.key = common_data.cert; - else if ((common_data.cert == NULL) && (common_data.key == NULL)) - { - common_data.cert = getenv("X509_USER_PROXY"); - if (common_data.cert != NULL) common_data.key = common_data.cert; - else - { - asprintf(&(common_data.cert), "/tmp/x509up_u%d", geteuid()); - - /* one fine day, we will check the proxy file for expiry too ... */ - - if (stat(common_data.cert, &statbuf) == 0) - common_data.key = common_data.cert; - else - { - common_data.cert = getenv("X509_USER_CERT"); - common_data.key = getenv("X509_USER_KEY"); - - userpasswd = getpwuid(geteuid()); - - if ((common_data.cert == NULL) && - (userpasswd != NULL) && - (userpasswd->pw_dir != NULL)) - asprintf(&(common_data.cert), "%s/.globus/usercert.pem", - userpasswd->pw_dir); - - if ((common_data.key == NULL) && - (userpasswd != NULL) && - (userpasswd->pw_dir != NULL)) - asprintf(&(common_data.key), "%s/.globus/userkey.pem", - userpasswd->pw_dir); - } - } - } - - if (common_data.capath == NULL) common_data.capath = getenv("X509_CERT_DIR"); - - if (common_data.capath == NULL) - common_data.capath = "/etc/grid-security/certificates"; - -#if (LIBCURL_VERSION_NUM < 0x070908) - /* libcurl before 7.9.8 doesnt support CURLOPT_CAPATH and the directory */ - - if ((common_data.capath != NULL) && - (stat(common_data.capath, &statbuf) == 0) && S_ISDIR(statbuf.st_mode)) - { - tmp_ca_roots = make_tmp_ca_roots(common_data.capath); - common_data.capath = tmp_ca_roots; - } -#endif - - executable = rindex(argv[0], '/'); - if (executable != NULL) executable++; - else executable = argv[0]; - - if (common_data.method == 0) /* command-line options override exec name */ - { - if (strcmp(executable,"htls")==0) common_data.method=HTCP_LIST; - else if (strcmp(executable,"htll")==0) common_data.method=HTCP_LONGLIST; - else if (strcmp(executable,"htrm")==0) common_data.method=HTCP_DELETE; - else if (strcmp(executable,"htmkdir")==0) common_data.method=HTCP_MKDIR; - } - - if ((common_data.method == HTCP_DELETE) || - (common_data.method == HTCP_LIST) || - (common_data.method == HTCP_MKDIR) || - (common_data.method == HTCP_LONGLIST)) - { - if (optind >= argc) - { - fprintf(stderr, "Must give at least 1 non-option argument\n\n"); - printsyntax(argv[0]); - return CURLE_URL_MALFORMAT; - } - - sources = (char **) malloc(sizeof(char *) * (1 + argc - optind)); - for (i=0; i < argc - optind; ++i) - { - sources[i] = argv[optind + i]; - - if ((common_data.method == HTCP_MKDIR) && - (sources[i][strlen(sources[i])-1] != '/')) - { - fprintf(stderr, "Argument \"%s\" is not a " - "directory URL (no trailing /)\n\n", sources[i]); - printsyntax(argv[0]); - return CURLE_URL_MALFORMAT; - } - } - - sources[i] = NULL; - - if (common_data.method == HTCP_DELETE) - anyerror = do_deletes(sources, &common_data); - else if (common_data.method == HTCP_MKDIR) - anyerror = do_mkdirs(sources, &common_data); - else if (common_data.method == HTCP_LONGLIST) - anyerror = do_listings(sources, &common_data, 1); - else anyerror = do_listings(sources, &common_data, 0); - - if (anyerror > 99) anyerror = CURLE_HTTP_RETURNED_ERROR; - - return anyerror; - } - - if (optind >= argc - 1) - { - fputs("Must give at least 2 non-option arguments\n\n", stderr); - printsyntax(argv[0]); - return CURLE_URL_MALFORMAT; - } - - sources = (char **) malloc(sizeof(char *) * (argc - optind)); - - for (i=0; i < (argc - optind - 1); ++i) - { - if (strncmp(argv[optind + i], "file:", 5) == 0) - sources[i] = &argv[optind + i][5]; - else sources[i] = argv[optind + i]; - - if (sources[i][0] == '\0') - { - fprintf(stderr, "Source argument %d is empty\n\n", i + 1); - printsyntax(argv[0]); - return CURLE_URL_MALFORMAT; - } - } - - sources[i] = NULL; - - if (strncmp(argv[optind + i], "file:", 5) == 0) - destination = &argv[optind + i][5]; - else destination = argv[optind + i]; - - if (destination[0] == '\0') - { - fputs("Destination argument is empty\n\n", stderr); - printsyntax(argv[0]); - return CURLE_URL_MALFORMAT; - } - - if ((argc - optind > 2) && (destination[strlen(destination)-1] != '/')) - { - fputs("For multiple sources, destination " - "must be a directory (end in /)\n\n", stderr); - printsyntax(argv[0]); - return CURLE_URL_MALFORMAT; - } - - if ((strncmp(destination, "http://", 7) == 0) || - (strncmp(destination, "https://", 8) == 0)) - common_data.method = HTCP_PUT; - else common_data.method = HTCP_GET; - - for (i=0; sources[i] != NULL; ++i) - { - if ((common_data.method == HTCP_PUT) && - ((strncmp(sources[i], "http://", 7) == 0) || - (strncmp(sources[i], "https://", 8) == 0))) - { - fputs("Cannot have both source and destination remote\n\n",stderr); - printsyntax(argv[0]); - return CURLE_URL_MALFORMAT; - } - - if ((common_data.method == HTCP_GET) && - ((strncmp(sources[i], "http://", 7) != 0) && - (strncmp(sources[i], "https://", 8) != 0))) - { - fputs("Cannot have both source and " - "destination local (for now)\n\n",stderr); - printsyntax(argv[0]); - return CURLE_URL_MALFORMAT; - } - } - - anyerror = do_copies(sources, destination, &common_data); - if (anyerror > 99) anyerror = CURLE_HTTP_RETURNED_ERROR; - - return anyerror; -} diff --git a/org.gridsite.core/src/htproxyput.c b/org.gridsite.core/src/htproxyput.c deleted file mode 100644 index 834bea2..0000000 --- a/org.gridsite.core/src/htproxyput.c +++ /dev/null @@ -1,565 +0,0 @@ -/* - Copyright (c) 2002-4, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/* - -Build with: - -gcc -lcurl -lssl -lcrypto -o grst-proxy-put grst-proxy-put.c libgridsite.a - -http://www.gridpp.ac.uk/authz/gridsite/ - -*/ - -#ifndef VERSION -#define VERSION "0.0.0" -#endif - -#define _GNU_SOURCE - -#include -#include -#include -#include - -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include - -#include - -#include "gridsite.h" - -#include "soapH.h" -#include "delegation.nsmap" - -#define USE_SOAP 0 -#define USE_G_HTTPS 1 -#define HTPROXY_PUT 0 - -int debugfunction(CURL *curl, curl_infotype type, char *s, size_t n, void *p) -{ - fwrite(s, sizeof(char), n, (FILE *) p); - - return 0; -} - -size_t parsegprheaders(void *ptr, size_t size, size_t nmemb, void *p) -{ - int i; - - if ((size * nmemb > 15) && - (strncmp((char *) ptr, "Delegation-ID: ", 15) == 0)) - { - *((char **) p) = malloc( size * nmemb - 14 ); - - memcpy(*((char **) p), &(((char *) ptr)[15]), size * nmemb - 15); - - for (i=0; i < size * nmemb - 15; ++i) - if (((*((char **) p))[i] == '\n') || ((*((char **) p))[i] == '\r')) - { - (*((char **) p))[i] = '\0'; /* drop trailing newline */ - break; - } - - (*((char **) p))[size * nmemb - 15] = '\0'; - } - - return size * nmemb; -} - -struct gprparams { char *req; size_t len; } ; - -size_t storegprbody(void *ptr, size_t size, size_t nmemb, void *p) -{ - ((struct gprparams *) p)->req = realloc( ((struct gprparams *) p)->req, - ((struct gprparams *) p)->len + size * nmemb + 1); - - memcpy( &((((struct gprparams *) p)->req)[((struct gprparams *) p)->len]), - ptr, size * nmemb); - - ((struct gprparams *) p)->len += size * nmemb; - - return size * nmemb; -} - -int GRSTgetProxyReq(CURL *curl, FILE *debugfp, char *delegid, char **reqtxt, - char *requrl, char *cert, char *key) -{ - char *delheader; - struct curl_slist *headerlist = NULL; - CURLcode res; - struct gprparams params; - - params.req = NULL; - params.len = 0; - - curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) ¶ms); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, storegprbody); - - curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM"); - curl_easy_setopt(curl, CURLOPT_SSLCERT, cert); - - curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM"); - curl_easy_setopt(curl, CURLOPT_SSLKEY, key); - curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, NULL); - -// curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, parsegprheaders); -// curl_easy_setopt(curl, CURLOPT_WRITEHEADER, (void *) delegid); - - curl_easy_setopt(curl, CURLOPT_CAPATH, "/etc/grid-security/certificates/"); - - curl_easy_setopt(curl, CURLOPT_URL, requrl); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "GET-PROXY-REQ"); - - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER,0); - curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST,0); - - asprintf(&delheader, "Delegation-ID: %s", delegid); - headerlist = curl_slist_append(headerlist, delheader); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); - - if (debugfp != NULL) - { - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); - curl_easy_setopt(curl, CURLOPT_DEBUGDATA, debugfp); - curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debugfunction); - } - - res = curl_easy_perform(curl); - - if (params.req != NULL) - { - params.req[params.len] = '\0'; - *reqtxt = params.req; - } - else *reqtxt = NULL; - - return (int) res; -} - -struct ppcparams{ char *cert; size_t len; }; - -size_t getppcbody(void *ptr, size_t size, size_t nmemb, void *p) -{ - size_t i; - - if (((struct ppcparams *) p)->len == 0) return 0; - - if (size * nmemb < ((struct ppcparams *) p)->len) i = size * nmemb; - else i = ((struct ppcparams *) p)->len; - - memcpy(ptr, ((struct ppcparams *) p)->cert, i); - - ((struct ppcparams *) p)->len -= i; - ((struct ppcparams *) p)->cert = &((((struct ppcparams *) p)->cert)[i+1]); - - return i; -} - -int GRSTputProxyCerts(CURL *curl, FILE *debugfp, char *delegid, char *certtxt, - char *requrl, char *cert, char *key) -{ - CURLcode res; - char *delheader; - long httpcode; - struct curl_slist *headerlist = NULL; - struct ppcparams params; - - params.cert = certtxt; - params.len = strlen(certtxt); - - curl_easy_setopt(curl, CURLOPT_READDATA, ¶ms); - curl_easy_setopt(curl, CURLOPT_READFUNCTION, getppcbody); - curl_easy_setopt(curl, CURLOPT_INFILESIZE, strlen(certtxt)); - curl_easy_setopt(curl, CURLOPT_UPLOAD, 1); - - curl_easy_setopt(curl, CURLOPT_NOBODY, 1); - - curl_easy_setopt(curl, CURLOPT_SSLCERTTYPE, "PEM"); - curl_easy_setopt(curl, CURLOPT_SSLCERT, cert); - - curl_easy_setopt(curl, CURLOPT_SSLKEYTYPE, "PEM"); - curl_easy_setopt(curl, CURLOPT_SSLKEY, key); -// curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, NULL); - - curl_easy_setopt(curl, CURLOPT_CAPATH, "/etc/grid-security/certificates/"); - - curl_easy_setopt(curl, CURLOPT_URL, requrl); - curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "PUT-PROXY-CERT"); - - headerlist = curl_slist_append(headerlist, - "Content-Type: application/x-x509-user-cert-chain"); - - asprintf(&delheader, "Delegation-ID: %s", delegid); - headerlist = curl_slist_append(headerlist, delheader); - curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist); - -curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0); -curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0); - - if (debugfp != NULL) - { - curl_easy_setopt(curl, CURLOPT_VERBOSE, 1); - curl_easy_setopt(curl, CURLOPT_DEBUGDATA, debugfp); - curl_easy_setopt(curl, CURLOPT_DEBUGFUNCTION, debugfunction); - } - - res = curl_easy_perform(curl); - - curl_easy_getinfo(curl, CURLINFO_HTTP_CODE, &httpcode); - - curl_slist_free_all(headerlist); - - free(delheader); - - return (int) res; -} - - -#if (LIBCURL_VERSION_NUM < 0x070908) -char *make_tmp_ca_roots(char *dir) -/* libcurl before 7.9.8 doesnt support CURLOPT_CAPATH and the directory, - so we make a temporary file with the concatenated CA root certs: that - is, all the files in that directory which end in .0 */ -{ - int ofd, ifd, c; - size_t size; - char tmp_ca_roots[] = "/tmp/.ca-roots-XXXXXX", buffer[4096], *s; - DIR *rootsDIR; - struct dirent *root_ent; - - if ((rootsDIR = opendir(dir)) == NULL) return NULL; - - if ((ofd = mkstemp(tmp_ca_roots)) == -1) - { - closedir(rootsDIR); - return NULL; - } - - while ((root_ent = readdir(rootsDIR)) != NULL) - { - if ((root_ent->d_name[0] != '.') && - (strlen(root_ent->d_name) > 2) && - (strncmp(&(root_ent->d_name[strlen(root_ent->d_name)-2]), - ".0", 2) == 0)) - { - asprintf(&s, "%s/%s", dir, root_ent->d_name); - ifd = open(s, O_RDONLY); - free(s); - - if (ifd != -1) - { - while ((size = read(ifd, buffer, sizeof(buffer))) > 0) - write(ofd, buffer, size); - - close(ifd); - } - } - } - - closedir(rootsDIR); - - if (close(ofd) == 0) return strdup(tmp_ca_roots); - - unlink(tmp_ca_roots); /* try to clean up if errors */ - - return NULL; -} -#endif - -void printsyntax(char *argv0) -{ - char *p; - - p = rindex(argv0, '/'); - if (p != NULL) ++p; - else p = argv0; - - fprintf(stderr, "%s [options] URL\n" - "(Version: %s)\n", p, VERSION); -} - -int main(int argc, char *argv[]) -{ - char *delegation_id = "", *reqtxt, *certtxt, *valid = NULL, - *cert = NULL, *key = NULL, *capath = NULL, *keycert; - struct ns__putProxyResponse *unused; - int option_index, c, protocol = USE_SOAP, noverify = 0, - method = HTPROXY_PUT, verbose = 0, fd, minutes; - struct soap soap_get, soap_put; - FILE *ifp, *ofp; - struct stat statbuf; - struct passwd *userpasswd; - struct option long_options[] = { {"verbose", 0, 0, 'v'}, - {"cert", 1, 0, 0}, - {"key", 1, 0, 0}, - {"capath", 1, 0, 0}, - {"soap", 0, 0, 0}, - {"g-https", 0, 0, 0}, - {"no-verify", 0, 0, 0}, - {"valid", 1, 0, 0}, - {"delegation-id",1, 0, 0}, - {"put", 0, 0, 0}, - {0, 0, 0, 0} }; - CURL *curl; - - if (argc == 1) - { - printsyntax(argv[0]); - return 0; - } - - while (1) - { - option_index = 0; - - c = getopt_long(argc, argv, "v", long_options, &option_index); - - if (c == -1) break; - else if (c == 0) - { - if (option_index == 1) cert = optarg; - else if (option_index == 2) key = optarg; - else if (option_index == 3) capath = optarg; - else if (option_index == 4) protocol = USE_SOAP; - else if (option_index == 5) protocol = USE_G_HTTPS; - else if (option_index == 6) noverify = 1; - else if (option_index == 7) valid = optarg; - else if (option_index == 8) delegation_id = optarg; - else if (option_index == 9) method = HTPROXY_PUT; - } - else if (c == 'v') ++verbose; - } - - if (optind + 1 != argc) - { - fprintf(stderr, "Must specify a target URL!\n"); - return 1; - } - - if (valid == NULL) minutes = 60 * 12; - else minutes = atoi(valid); - - if (verbose) fprintf(stderr, "Proxy valid for %d minutes\n", minutes); - - ERR_load_crypto_strings (); - OpenSSL_add_all_algorithms(); - - if ((cert == NULL) && (key != NULL)) cert = key; - else if ((cert != NULL) && (key == NULL)) key = cert; - else if ((cert == NULL) && (key == NULL)) - { - cert = getenv("X509_USER_PROXY"); - if (cert != NULL) key = cert; - else - { - asprintf(&(cert), "/tmp/x509up_u%d", geteuid()); - - /* one fine day, we will check the proxy file for - expiry too to avoid suprises when we try to use it ... */ - - if (stat(cert, &statbuf) == 0) key = cert; - else - { - cert = getenv("X509_USER_CERT"); - key = getenv("X509_USER_KEY"); - - userpasswd = getpwuid(geteuid()); - - if ((cert == NULL) && - (userpasswd != NULL) && - (userpasswd->pw_dir != NULL)) - asprintf(&(cert), "%s/.globus/usercert.pem", - userpasswd->pw_dir); - - if ((key == NULL) && - (userpasswd != NULL) && - (userpasswd->pw_dir != NULL)) - asprintf(&(key), "%s/.globus/userkey.pem", - userpasswd->pw_dir); - - } - } - } - - if (capath == NULL) capath = getenv("X509_CERT_DIR"); - if (capath == NULL) capath = "/etc/grid-security/certificates"; - - if (verbose) fprintf(stderr, "key=%s\ncert=%s\ncapath=%s\n", - key, cert, capath); - -#if (LIBCURL_VERSION_NUM < 0x070908) - /* libcurl before 7.9.8 doesnt support CURLOPT_CAPATH and the directory */ - - if ((capath != NULL) && - (stat(capath, &statbuf) == 0) && S_ISDIR(statbuf.st_mode)) - { - tmp_ca_roots = make_tmp_ca_roots(capath); - capath = tmp_ca_roots; - } -#endif - - if (protocol == USE_G_HTTPS) - { - if (verbose) fprintf(stderr, "Using G-HTTPS delegation protocol\n"); - - if (verbose) fprintf(stderr, "Delegation-ID: %s\n", delegation_id); - - curl_global_init(CURL_GLOBAL_DEFAULT); - curl = curl_easy_init(); - -// curl_easy_setopt(curl, CURLOPT_SSLKEYPASSWD, NULL); - - GRSTgetProxyReq(curl, stderr, delegation_id, &reqtxt, - argv[optind], cert, key); - - if (GRSTx509MakeProxyCert(&certtxt, stderr, reqtxt, cert, key, minutes) - != GRST_RET_OK) - { - return 1; - } - - GRSTputProxyCerts(curl, stderr, delegation_id, certtxt, - argv[optind], cert, key); - - curl_easy_cleanup(curl); - curl_global_cleanup(); - - return 0; - } - else if (protocol == USE_SOAP) - { - if (strcmp(key, cert) != 0) /* we have to concatenate for gSOAP */ - { - keycert = strdup("/tmp/XXXXXX"); - - fd = mkstemp(keycert); - ofp = fdopen(fd, "w"); - - ifp = fopen(key, "r"); - while ((c = fgetc(ifp)) != EOF) fputc(c, ofp); - fclose(ifp); - - ifp = fopen(cert, "r"); - while ((c = fgetc(ifp)) != EOF) fputc(c, ofp); - fclose(ifp); - - fclose(ofp); - - if (verbose) fprintf(stderr, "Created %s key/cert file\n", keycert); - } - else keycert = key; - - if (verbose) - { - fprintf(stderr, "Using SOAP delegation protocol\n"); - fprintf(stderr, "Delegation-ID: %s\n", delegation_id); - fprintf(stderr, "Send getProxyReq to service\n"); - } - - soap_init(&soap_get); - - if (soap_ssl_client_context(&soap_get, - SOAP_SSL_DEFAULT, - keycert, - "", - NULL, - capath, - NULL)) - { - soap_print_fault(&soap_get, stderr); - return 1; - } - - soap_call_ns__getProxyReq(&soap_get, - argv[optind], /* HTTPS url of service */ - "", /* no password on proxy */ - delegation_id, - &reqtxt); - - if (soap_get.error) - { - soap_print_fault(&soap_get, stderr); - return 1; - } - - if (verbose) fprintf(stderr, "reqtxt:\n%s", reqtxt); - - if (GRSTx509MakeProxyCert(&certtxt, stderr, reqtxt, cert, key, minutes) - != GRST_RET_OK) - { - return 1; - } - - soap_init(&soap_put); - - if (verbose) fprintf(stderr, "Send putProxy to service:\n%s\n", certtxt); - - if (soap_ssl_client_context(&soap_put, - SOAP_SSL_DEFAULT, - keycert, - "", - NULL, - capath, - NULL)) - { - soap_print_fault(&soap_put, stderr); - return 1; - } - - soap_call_ns__putProxy(&soap_put, argv[optind], "", delegation_id, - certtxt, unused); - if (soap_put.error) - { - soap_print_fault(&soap_put, stderr); - return 1; - } - - return 0; - } - - /* weirdness */ -} - diff --git a/org.gridsite.core/src/mod_gridsite.c b/org.gridsite.core/src/mod_gridsite.c deleted file mode 100644 index 78d853c..0000000 --- a/org.gridsite.core/src/mod_gridsite.c +++ /dev/null @@ -1,2357 +0,0 @@ -/* - Copyright (c) 2003-4, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/*------------------------------------------------------------------* - * This program is part of GridSite: http://www.gridsite.org/ * - *------------------------------------------------------------------*/ - -#ifndef VERSION -#define VERSION "x.x.x" -#endif - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - - -#include "mod_ssl-private.h" - -#include "gridsite.h" - -#ifndef UNSET -#define UNSET -1 -#endif - -module AP_MODULE_DECLARE_DATA gridsite_module; - -typedef struct -{ - int auth; - int envs; - int format; - int indexes; - char *indexheader; - int gridsitelink; - char *adminfile; - char *adminuri; - char *helpuri; - char *dnlists; - char *dnlistsuri; - char *adminlist; - int gsiproxylimit; - char *unzip; - char *methods; - char *editable; - char *headfile; - char *footfile; - int downgrade; - char *authcookiesdir; - int soap2cgi; -} mod_gridsite_cfg; /* per-directory config choices */ - - -typedef struct -{ - xmlDocPtr doc; -// char *outbuffer; -} soap2cgi_ctx; /* store per-request context for Soap2cgi in/out filters */ - -static const char Soap2cgiFilterName[]="Soap2cgiFilter"; - -static void mod_gridsite_soap2cgi_insert(request_rec *r) -{ - mod_gridsite_cfg *conf; - soap2cgi_ctx *ctx; - - conf = (mod_gridsite_cfg *) ap_get_module_config(r->per_dir_config, - &gridsite_module); - - if (conf->soap2cgi) - { - ctx = (soap2cgi_ctx *) malloc(sizeof(soap2cgi_ctx)); - ctx->doc = NULL; - - ap_add_output_filter(Soap2cgiFilterName, ctx, r, r->connection); - - ap_add_input_filter(Soap2cgiFilterName, NULL, r, r->connection); - } -} - -xmlNodePtr find_one_child(xmlNodePtr parent_node, char *name) -{ - xmlNodePtr cur; - - for (cur = parent_node->children; cur != NULL; cur = cur->next) - { - if ((cur->type == XML_ELEMENT_NODE) && - (strcmp(cur->name, name) == 0)) return cur; - } - - return NULL; -} - -int add_one_node(xmlDocPtr doc, char *line) -{ - char *p, *name, *aftername, *attrname = NULL, *value = NULL; - xmlNodePtr cur, cur_child; - - cur = xmlDocGetRootElement(doc); - - p = index(line, '='); - if (p == NULL) return 1; - - *p = '\0'; - value = &p[1]; - - name = line; - - while (1) /* go through each .-deliminated segment of line[] */ - { - if ((p = index(name, '.')) != NULL) - { - *p = '\0'; - aftername = &p[1]; - } - else aftername = &name[strlen(name)]; - - if ((p = index(name, '_')) != NULL) - { - *p = '\0'; - attrname = &p[1]; - } - - cur_child = find_one_child(cur, name); - - if (cur_child == NULL) - cur_child = xmlNewChild(cur, NULL, name, NULL); - - cur = cur_child; - - name = aftername; - - if (attrname != NULL) - { - xmlSetProp(cur, attrname, value); - return 0; - } - - if (*name == '\0') - { - xmlNodeSetContent(cur, value); - return 0; - } - } -} - -static apr_status_t mod_gridsite_soap2cgi_out(ap_filter_t *f, - apr_bucket_brigade *bbIn) -{ - char *p, *name, *outbuffer; - request_rec *r = f->r; - conn_rec *c = r->connection; - apr_bucket *bucketIn, *pbktEOS; - apr_bucket_brigade *bbOut; - - const char *data; - apr_size_t len; - char *buf; - apr_size_t n; - apr_bucket *pbktOut; - - soap2cgi_ctx *ctx; - xmlNodePtr root_node = NULL; - xmlBufferPtr buff; - - ctx = (soap2cgi_ctx *) f->ctx; - -// LIBXML_TEST_VERSION; - - bbOut = apr_brigade_create(r->pool, c->bucket_alloc); - - if (ctx->doc == NULL) - { - ctx->doc = xmlNewDoc("1.0"); - - root_node = xmlNewNode(NULL, "Envelope"); - xmlDocSetRootElement(ctx->doc, root_node); - - xmlNewChild(root_node, NULL, "Header", NULL); - xmlNewChild(root_node, NULL, "Body", NULL); - } - - apr_brigade_pflatten(bbIn, &outbuffer, &len, r->pool); - - /* split up buffer and feed each line to add_one_node() */ - - name = outbuffer; - - while (*name != '\0') - { - p = index(name, '\n'); - if (p != NULL) - { - *p = '\0'; - ++p; - } - else p = &name[strlen(name)]; /* point to final NUL */ - - add_one_node(ctx->doc, name); - - name = p; - } - - APR_BRIGADE_FOREACH(bucketIn, bbIn) - { - if (APR_BUCKET_IS_EOS(bucketIn)) - { - /* write out XML tree we have built */ - - buff = xmlBufferCreate(); - xmlNodeDump(buff, ctx->doc, root_node, 0, 0); - -// TODO: simplify/reduce number of copies or libxml vs APR buffers? - - buf = (char *) xmlBufferContent(buff); - - pbktOut = apr_bucket_heap_create(buf, strlen(buf), NULL, - c->bucket_alloc); - - APR_BRIGADE_INSERT_TAIL(bbOut, pbktOut); - - xmlBufferFree(buff); - - pbktEOS = apr_bucket_eos_create(c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(bbOut, pbktEOS); - - continue; - } - } - - return ap_pass_brigade(f->next, bbOut); -} - -static apr_status_t mod_gridsite_soap2cgi_in(ap_filter_t *f, - apr_bucket_brigade *pbbOut, - ap_input_mode_t eMode, - apr_read_type_e eBlock, - apr_off_t nBytes) -{ - request_rec *r = f->r; - conn_rec *c = r->connection; -// CaseFilterInContext *pCtx; - apr_status_t ret; - -#ifdef NEVERDEFINED - - ret = ap_get_brigade(f->next, pCtx->pbbTmp, eMode, eBlock, nBytes); - - if (!(pCtx = f->ctx)) { - f->ctx = pCtx = apr_palloc(r->pool, sizeof *pCtx); - pCtx->pbbTmp = apr_brigade_create(r->pool, c->bucket_alloc); - } - - if (APR_BRIGADE_EMPTY(pCtx->pbbTmp)) { - ret = ap_get_brigade(f->next, pCtx->pbbTmp, eMode, eBlock, nBytes); - - if (eMode == AP_MODE_EATCRLF || ret != APR_SUCCESS) - return ret; - } - - while(!APR_BRIGADE_EMPTY(pCtx->pbbTmp)) { - apr_bucket *pbktIn = APR_BRIGADE_FIRST(pCtx->pbbTmp); - apr_bucket *pbktOut; - const char *data; - apr_size_t len; - char *buf; - int n; - - /* It is tempting to do this... - * APR_BUCKET_REMOVE(pB); - * APR_BRIGADE_INSERT_TAIL(pbbOut,pB); - * and change the case of the bucket data, but that would be wrong - * for a file or socket buffer, for example... - */ - - if(APR_BUCKET_IS_EOS(pbktIn)) { - APR_BUCKET_REMOVE(pbktIn); - APR_BRIGADE_INSERT_TAIL(pbbOut, pbktIn); - break; - } - - ret=apr_bucket_read(pbktIn, &data, &len, eBlock); - if(ret != APR_SUCCESS) - return ret; - - buf = malloc(len); - for(n=0 ; n < len ; ++n) - buf[n] = apr_toupper(data[n]); - - pbktOut = apr_bucket_heap_create(buf, len, 0, c->bucket_alloc); - APR_BRIGADE_INSERT_TAIL(pbbOut, pbktOut); - apr_bucket_delete(pbktIn); - } -#endif - - return APR_SUCCESS; -} - -char *make_admin_footer(request_rec *r, mod_gridsite_cfg *conf, - int isdirectory) -/* - make string holding last modified text and admin links -*/ -{ - char *out, *https, *p, *dn = NULL, *file = NULL, *permstr = NULL, - *temp, modified[99], *dir_uri, *grst_cred_0 = NULL; - GRSTgaclPerm perm = GRST_PERM_NONE; - struct tm mtime_tm; - time_t mtime_time; - - https = (char *) apr_table_get(r->subprocess_env, "HTTPS"); - - dir_uri = apr_pstrdup(r->pool, r->uri); - p = rindex(dir_uri, '/'); - - if (p == NULL) return ""; - - file = apr_pstrdup(r->pool, &p[1]); - p[1] = '\0'; - /* dir_uri always gets both a leading and a trailing slash */ - - out = apr_pstrdup(r->pool, "

\n"); - - if (!isdirectory) - { - mtime_time = apr_time_sec(r->finfo.mtime); - - localtime_r(&mtime_time, &mtime_tm); - strftime(modified, sizeof(modified), - "%a %e %B %Y", &mtime_tm); - temp = apr_psprintf(r->pool,"


Last modified %s\n", modified); - out = apr_pstrcat(r->pool, out, temp, NULL); - - if ((conf->adminuri != NULL) && - (conf->adminuri[0] != '\0') && - (conf->adminfile != NULL) && - (conf->adminfile[0] != '\0') && - (strncmp(file, GRST_HIST_PREFIX, sizeof(GRST_HIST_PREFIX)-1) != 0)) - { - temp = apr_psprintf(r->pool, - ". " - "View page history\n", - conf->adminfile, file); - out = apr_pstrcat(r->pool, out, temp, NULL); - } - } - - out = apr_pstrcat(r->pool, out, "
", NULL); - - if (r->connection->notes != NULL) - grst_cred_0 = (char *) - apr_table_get(r->connection->notes, "GRST_CRED_0"); - - if ((grst_cred_0 != NULL) && - (strncmp(grst_cred_0, "X509USER ", sizeof("X509USER")) == 0)) - { - p = index(grst_cred_0, ' '); - if (p != NULL) - { - p = index(++p, ' '); - if (p != NULL) - { - p = index(++p, ' '); - if (p != NULL) - { - p = index(++p, ' '); - if (p != NULL) dn = p; - } - } - } - } - - if (dn != NULL) - { - temp = apr_psprintf(r->pool, "You are %s
\n", dn); - out = apr_pstrcat(r->pool, out, temp, NULL); - - if (r->notes != NULL) - permstr = (char *) apr_table_get(r->notes, "GRST_PERM"); - - if ((permstr != NULL) && - (conf->adminuri != NULL) && - (conf->adminuri[0] != '\0') && - (conf->adminfile != NULL) && - (conf->adminfile[0] != '\0')) - { - sscanf(permstr, "%d", &perm); - - if (!isdirectory && - GRSTgaclPermHasWrite(perm) && - (strncmp(file, GRST_HIST_PREFIX, - sizeof(GRST_HIST_PREFIX) - 1) != 0)) - { - temp = apr_psprintf(r->pool, - "" - "Edit page .\n", conf->adminfile, file); - out = apr_pstrcat(r->pool, out, temp, NULL); - } - - if (GRSTgaclPermHasList(perm) || GRSTgaclPermHasWrite(perm)) - { - temp = apr_psprintf(r->pool, - "Manage directory .\n", - dir_uri, conf->adminfile); - - out = apr_pstrcat(r->pool, out, temp, NULL); - } - } - } - - if ((https != NULL) && (strcasecmp(https, "on") == 0)) - temp = apr_psprintf(r->pool, - "Switch to HTTP \n", - r->server->server_hostname, r->unparsed_uri); - else temp = apr_psprintf(r->pool, - "Switch to HTTPS \n", - r->server->server_hostname, r->unparsed_uri); - - out = apr_pstrcat(r->pool, out, temp, NULL); - - if ((conf->helpuri != NULL) && (conf->helpuri[0] != '\0')) - { - temp = apr_psprintf(r->pool, - ". Website Help\n", conf->helpuri); - out = apr_pstrcat(r->pool, out, temp, NULL); - } - - if ((!isdirectory) && - (conf->adminuri != NULL) && - (conf->adminuri[0] != '\0') && - (conf->adminfile != NULL) && - (conf->adminfile[0] != '\0')) - { - temp = apr_psprintf(r->pool, ". " - "Print View\n", conf->adminfile, file); - out = apr_pstrcat(r->pool, out, temp, NULL); - } - - if (conf->gridsitelink) - { - temp = apr_psprintf(r->pool, - ". Built with " - "GridSite %s\n", VERSION); - out = apr_pstrcat(r->pool, out, temp, NULL); - } - - out = apr_pstrcat(r->pool, out, "\n
\n", NULL); - - return out; -} - -int html_format(request_rec *r, mod_gridsite_cfg *conf) -/* - try to do GridSite formatting of .html files (NOT .shtml etc) -*/ -{ - int i, fd, errstatus; - char *buf, *p, *file, *s, *head_formatted, *header_formatted, - *body_formatted, *admin_formatted, *footer_formatted; - size_t length; - struct stat statbuf; - apr_file_t *fp; - - if (r->finfo.filetype == APR_NOFILE) return HTTP_NOT_FOUND; - - if (apr_file_open(&fp, r->filename, APR_READ, 0, r->pool) != 0) - return HTTP_INTERNAL_SERVER_ERROR; - - file = rindex(r->uri, '/'); - if (file != NULL) ++file; /* file points to name without path */ - - buf = apr_palloc(r->pool, (size_t)(r->finfo.size + 1)); - length = r->finfo.size; - apr_file_read(fp, buf, &length); - buf[r->finfo.size] = '\0'; - apr_file_close(fp); - - /* **** try to find a header file in this or parent directories **** */ - - /* first make a buffer big enough to hold path names we want to try */ - fd = -1; - s = malloc(strlen(r->filename) + strlen(conf->headfile) + 1); - strcpy(s, r->filename); - - for (;;) - { - p = rindex(s, '/'); - if (p == NULL) break; /* failed to find one */ - p[1] = '\0'; - strcat(p, conf->headfile); - - fd = open(s, O_RDONLY); - if (fd != -1) break; /* found one */ - - *p = '\0'; - } - - free(s); - - if (fd == -1) /* not found, so set up not to output one */ - { - head_formatted = apr_pstrdup(r->pool, ""); - header_formatted = apr_pstrdup(r->pool, ""); - body_formatted = buf; - } - else /* found a header file, so set up head and body to surround it */ - { - fstat(fd, &statbuf); - header_formatted = apr_palloc(r->pool, statbuf.st_size + 1); - read(fd, header_formatted, statbuf.st_size); - header_formatted[statbuf.st_size] = '\0'; - close(fd); - - p = strstr(buf, "pool, ""); - body_formatted = buf; - } - else - { - *p = '\0'; - head_formatted = buf; - ++p; - - while ((*p != '>') && (*p != '\0')) ++p; - - if (*p == '\0') - { - body_formatted = p; - } - else - { - *p = '\0'; - ++p; - body_formatted = p; - } - } - } - - /* **** remove closing tag from body **** */ - - p = strstr(body_formatted, "filename) + strlen(conf->footfile)); - strcpy(s, r->filename); - - for (;;) - { - p = rindex(s, '/'); - if (p == NULL) break; /* failed to find one */ - - p[1] = '\0'; - strcat(p, conf->footfile); - - fd = open(s, O_RDONLY); - if (fd != -1) break; /* found one */ - - *p = '\0'; - } - - free(s); - - if (fd == -1) /* failed to find a footer, so set up empty default */ - { - footer_formatted = apr_pstrdup(r->pool, ""); - } - else /* found a footer, so set up to use it */ - { - fstat(fd, &statbuf); - footer_formatted = apr_palloc(r->pool, statbuf.st_size + 1); - read(fd, footer_formatted, statbuf.st_size); - footer_formatted[statbuf.st_size] = '\0'; - close(fd); - } - - /* **** can now calculate the Content-Length and output headers **** */ - - length = strlen(head_formatted) + strlen(header_formatted) + - strlen(body_formatted) + strlen(admin_formatted) + - strlen(footer_formatted); - - ap_set_content_length(r, length); - ap_set_content_type(r, "text/html"); - - /* ** output the HTTP body (HTML Head+Body) ** */ - - ap_rputs(head_formatted, r); - ap_rputs(header_formatted, r); - ap_rputs(body_formatted, r); - ap_rputs(admin_formatted, r); - ap_rputs(footer_formatted, r); - - return OK; -} - -int html_dir_list(request_rec *r, mod_gridsite_cfg *conf) -/* - output HTML directory listing, with level of formatting controlled - by GridSiteHtmlFormat/conf->format -*/ -{ - int i, fd, n; - char *buf, *p, *s, *head_formatted, *header_formatted, - *body_formatted, *admin_formatted, *footer_formatted, *temp, - modified[99], *d_namepath, *indexheaderpath, *indexheadertext; - size_t length; - struct stat statbuf; - struct tm mtime_tm; - struct dirent **namelist; - - if (r->finfo.filetype == APR_NOFILE) return HTTP_NOT_FOUND; - - head_formatted = apr_psprintf(r->pool, - "Directory listing %s\n", r->uri); - - if (conf->format) - { - /* **** try to find a header file in this or parent directories **** */ - - /* first make a buffer big enough to hold path names we want to try */ - fd = -1; - s = malloc(strlen(r->filename) + strlen(conf->headfile) + 1); - strcpy(s, r->filename); - - for (;;) - { - p = rindex(s, '/'); - if (p == NULL) break; /* failed to find one */ - p[1] = '\0'; - strcat(p, conf->headfile); - - fd = open(s, O_RDONLY); - if (fd != -1) break; /* found one */ - - *p = '\0'; - } - - free(s); - - if (fd == -1) /* not found, so set up to output sensible default */ - { - header_formatted = apr_pstrdup(r->pool, ""); - } - else /* found a header file, so set up head and body to surround it */ - { - fstat(fd, &statbuf); - header_formatted = apr_palloc(r->pool, statbuf.st_size + 1); - read(fd, header_formatted, statbuf.st_size); - header_formatted[statbuf.st_size] = '\0'; - close(fd); - } - } - else header_formatted = apr_pstrdup(r->pool, ""); - - body_formatted = apr_psprintf(r->pool, - "

Directory listing %s

\n", r->uri); - - if (conf->indexheader != NULL) - { - indexheaderpath = apr_psprintf(r->pool, "%s/%s", r->filename, - conf->indexheader); - fd = open(indexheaderpath, O_RDONLY); - if (fd != -1) - { - fstat(fd, &statbuf); - indexheadertext = apr_palloc(r->pool, statbuf.st_size + 1); - read(fd, indexheadertext, statbuf.st_size); - indexheadertext[statbuf.st_size] = '\0'; - close(fd); - - body_formatted = apr_pstrcat(r->pool, body_formatted, - indexheadertext, NULL); - } - } - - body_formatted = apr_pstrcat(r->pool, body_formatted, "

\n", NULL); - - if (r->unparsed_uri[1] != '\0') - body_formatted = apr_pstrcat(r->pool, body_formatted, - "\n", - NULL); - - n = scandir(r->filename, &namelist, 0, versionsort); - while (n--) - { - if ((namelist[n]->d_name[0] != '.') && - ((conf->indexheader == NULL) || - (strcmp(conf->indexheader, namelist[n]->d_name) != 0))) - { - d_namepath = apr_psprintf(r->pool, "%s/%s", r->filename, - namelist[n]->d_name); - stat(d_namepath, &statbuf); - - localtime_r(&(statbuf.st_mtime), &mtime_tm); - strftime(modified, sizeof(modified), - "", - &mtime_tm); - - if (S_ISDIR(statbuf.st_mode)) - temp = apr_psprintf(r->pool, - "" - "%s\n", - namelist[n]->d_name, statbuf.st_size, statbuf.st_mtime, - namelist[n]->d_name, - statbuf.st_size, modified); - else temp = apr_psprintf(r->pool, - "" - "%s\n", - namelist[n]->d_name, statbuf.st_size, statbuf.st_mtime, - namelist[n]->d_name, - statbuf.st_size, modified); - - body_formatted = apr_pstrcat(r->pool,body_formatted,temp,NULL); - } - - free(namelist[n]); - } - - free(namelist); - - body_formatted = apr_pstrcat(r->pool, body_formatted, "
[Parent directory]
%R%e %b %y
" - "%s/%ld
" - "%s%ld
\n", NULL); - - if (conf->format) - { - /* **** set up dynamic part of footer to go at end of body **** */ - - admin_formatted = make_admin_footer(r, conf, TRUE); - - /* **** try to find a footer file in this or parent directories **** */ - - /* first make a buffer big enough to hold path names we want to try */ - fd = -1; - s = malloc(strlen(r->filename) + strlen(conf->footfile)); - strcpy(s, r->filename); - - for (;;) - { - p = rindex(s, '/'); - if (p == NULL) break; /* failed to find one */ - - p[1] = '\0'; - strcat(p, conf->footfile); - - fd = open(s, O_RDONLY); - if (fd != -1) break; /* found one */ - - *p = '\0'; - } - - free(s); - - if (fd == -1) /* failed to find a footer, so use standard default */ - { - footer_formatted = apr_pstrdup(r->pool, ""); - } - else /* found a footer, so set up to use it */ - { - fstat(fd, &statbuf); - footer_formatted = apr_palloc(r->pool, statbuf.st_size + 1); - read(fd, footer_formatted, statbuf.st_size); - footer_formatted[statbuf.st_size] = '\0'; - close(fd); - } - } - else - { - admin_formatted = apr_pstrdup(r->pool, ""); - footer_formatted = apr_pstrdup(r->pool, ""); - } - - /* **** can now calculate the Content-Length and output headers **** */ - - length = strlen(head_formatted) + strlen(header_formatted) + - strlen(body_formatted) + strlen(admin_formatted) + - strlen(footer_formatted); - - ap_set_content_length(r, length); - ap_set_content_type(r, "text/html"); - - /* ** output the HTTP body (HTML Head+Body) ** */ - - ap_rputs(head_formatted, r); - ap_rputs(header_formatted, r); - ap_rputs(body_formatted, r); - ap_rputs(admin_formatted, r); - ap_rputs(footer_formatted, r); - - return OK; -} - -int http_downgrade(request_rec *r, mod_gridsite_cfg *conf) -{ - int i; - char *httpurl, *filetemplate, *cookievalue, *envname_i, - *grst_cred_i, expires_str[APR_RFC822_DATE_LEN]; - apr_uint64_t gridauthcookie; - apr_table_t *env; - apr_time_t expires_time; - apr_file_t *fp; - - /* create random cookie and gridauthcookie file */ - - if (apr_generate_random_bytes((char *) &gridauthcookie, - sizeof(gridauthcookie)) - != APR_SUCCESS) return HTTP_INTERNAL_SERVER_ERROR; - - filetemplate = apr_psprintf(r->pool, "%s/%016llxXXXXXX", - ap_server_root_relative(r->pool, - conf->authcookiesdir), - gridauthcookie); - - if (apr_file_mktemp(&fp, - filetemplate, - APR_CREATE | APR_WRITE | APR_EXCL, - r->pool) - != APR_SUCCESS) return HTTP_INTERNAL_SERVER_ERROR; - - expires_time = apr_time_now() + apr_time_from_sec(300); - /* onetime cookies are valid for only 5 mins! */ - - apr_file_printf(fp, "expires=%lu\ndomain=%s\npath=%s\nonetime=yes\n", - (time_t) apr_time_sec(expires_time), r->hostname, r->uri); - - for (i=0; ; ++i) - { - envname_i = apr_psprintf(r->pool, "GRST_CRED_%d", i); - if (grst_cred_i = (char *) - apr_table_get(r->connection->notes, envname_i)) - { - apr_file_printf(fp, "%s=%s\n", envname_i, grst_cred_i); - } - else break; /* GRST_CRED_i are numbered consecutively */ - } - - if (apr_file_close(fp) != APR_SUCCESS) - { - apr_file_remove(filetemplate, r->pool); /* try to clean up */ - return HTTP_INTERNAL_SERVER_ERROR; - } - - /* send redirection header back to client */ - - cookievalue = rindex(filetemplate, '/'); - if (cookievalue != NULL) ++cookievalue; - else cookievalue = filetemplate; - - apr_rfc822_date(expires_str, expires_time); - - apr_table_add(r->headers_out, - apr_pstrdup(r->pool, "Set-Cookie"), - apr_psprintf(r->pool, - "GRID_AUTH_ONETIME=%s; " - "expires=%s; " - "domain=%s; " - "path=%s", - cookievalue, expires_str, r->hostname, r->uri)); - - httpurl = apr_pstrcat(r->pool, "http://", r->hostname, - ap_escape_uri(r->pool, r->uri), NULL); - apr_table_setn(r->headers_out, apr_pstrdup(r->pool, "Location"), httpurl); - - r->status = HTTP_MOVED_TEMPORARILY; - return OK; -} - -int http_put_method(request_rec *r, mod_gridsite_cfg *conf) -{ - char buf[2048]; - size_t length; - int retcode; - apr_file_t *fp; - - /* *** check if directory creation: PUT /.../ *** */ - - if ((r->unparsed_uri != NULL) && - (r->unparsed_uri[0] != '\0') && - (r->unparsed_uri[strlen(r->unparsed_uri) - 1] == '/')) - { - if (apr_dir_make(r->filename, APR_UREAD | APR_UWRITE | APR_UEXECUTE, - r->pool) != 0) return HTTP_INTERNAL_SERVER_ERROR; - - ap_set_content_length(r, 0); - ap_set_content_type(r, "text/html"); - return OK; - } - - /* *** otherwise assume trying to create a regular file *** */ - - if (apr_file_open(&fp, r->filename, APR_WRITE | APR_CREATE | APR_BUFFERED, - APR_UREAD | APR_UWRITE, r->pool) != 0) return HTTP_INTERNAL_SERVER_ERROR; - -// TODO: need to add Range: support at some point too - - retcode = ap_setup_client_block(r, REQUEST_CHUNKED_DECHUNK); - if (retcode == OK) - { - if (ap_should_client_block(r)) - while ((length = ap_get_client_block(r, buf, sizeof(buf))) > 0) - if (apr_file_write(fp, buf, &length) != 0) - { - retcode = HTTP_INTERNAL_SERVER_ERROR; - break; - } - - ap_set_content_length(r, 0); - ap_set_content_type(r, "text/html"); - } - - if (apr_file_close(fp) != 0) return HTTP_INTERNAL_SERVER_ERROR; - - return retcode; -} - -int http_delete_method(request_rec *r, mod_gridsite_cfg *conf) -{ - if (remove(r->filename) != 0) return HTTP_FORBIDDEN; - - ap_set_content_length(r, 0); - ap_set_content_type(r, "text/html"); - - return OK; -} - -static int mod_gridsite_dir_handler(request_rec *r, mod_gridsite_cfg *conf) -/* - handler switch for directories -*/ -{ - /* *** is this a write method? only possible if GridSiteAuth on *** */ - - if (conf->auth) - { - if ((r->method_number == M_PUT) && - (conf->methods != NULL) && - (strstr(conf->methods, " PUT " ) != NULL)) - return http_put_method(r, conf); - - if ((r->method_number == M_DELETE) && - (conf->methods != NULL) && - (strstr(conf->methods, " DELETE ") != NULL)) - return http_delete_method(r, conf); - } - - /* *** directory listing? *** */ - - if ((r->method_number == M_GET) && (conf->indexes)) - return html_dir_list(r, conf); /* directory listing */ - - return DECLINED; /* *** nothing to see here, move along *** */ -} - -static int mod_gridsite_nondir_handler(request_rec *r, mod_gridsite_cfg *conf) -/* - one big handler switch for everything other than directories, since we - might be responding to MIME * / * for local PUT, MOVE, COPY and DELETE, - and GET inside ghost directories. -*/ -{ - char *downgradesize; - apr_off_t numericsize; - - /* *** is this a write method or HTTP downgrade? - only possible if GridSiteAuth on *** */ - - if (conf->auth) - { - if ((conf->downgrade) && - ((downgradesize = (char *) apr_table_get(r->headers_in, - "HTTP-Downgrade-Size")) != NULL) && - ((numericsize = (apr_off_t) atoll(downgradesize)) >= 0) && - -// TODO: what if we're pointing at a CGI or some dynamic content??? - (((r->method_number == M_GET) && (r->finfo.size >= numericsize)) - || (r->method_number == M_PUT)) && - - (strcasecmp(apr_table_get(r->subprocess_env, "HTTPS"), "on") == 0)) - return http_downgrade(r, conf); - - if ((r->method_number == M_PUT) && - (conf->methods != NULL) && - (strstr(conf->methods, " PUT " ) != NULL)) - return http_put_method(r, conf); - - if ((r->method_number == M_DELETE) && - (conf->methods != NULL) && - (strstr(conf->methods, " DELETE ") != NULL)) - return http_delete_method(r, conf); - } - - /* *** check if a special ghost admin CGI *** */ - - if (conf->adminfile && conf->adminuri && - (strlen(r->filename) > strlen(conf->adminfile) + 1) && - (strcmp(&(r->filename[strlen(r->filename) - strlen(conf->adminfile)]), - conf->adminfile) == 0) && - (r->filename[strlen(r->filename)-strlen(conf->adminfile)-1] == '/') && - ((r->method_number == M_POST) || - (r->method_number == M_GET))) - { - ap_internal_redirect(conf->adminuri, r); - return OK; - } - - /* *** finally look for .html files that we should format *** */ - - if ((conf->format) && /* conf->format set by GridSiteHtmlFormat on */ - (strlen(r->filename) > 5) && - (strcmp(&(r->filename[strlen(r->filename)-5]), ".html") == 0) && - (r->method_number == M_GET)) return html_format(r, conf); - - return DECLINED; /* *** nothing to see here, move along *** */ -} - -static void recurse4dirlist(char *dirname, time_t *dirs_time, - char *fulluri, int fullurilen, - char *encfulluri, int enclen, - apr_pool_t *pool, char **body, - int recurse_level) -/* try to find DN Lists in dir[] and its subdirs that match the fulluri[] - prefix. add blobs of HTML to body as they are found. */ -{ - char *unencname, modified[99], *oneline, *d_namepath; - DIR *oneDIR; - struct dirent *onedirent; - struct tm mtime_tm; - size_t length; - struct stat statbuf; - - if ((stat(dirname, &statbuf) != 0) || - (!S_ISDIR(statbuf.st_mode)) || - ((oneDIR = opendir(dirname)) == NULL)) return; - - if (statbuf.st_mtime > *dirs_time) *dirs_time = statbuf.st_mtime; - - while ((onedirent = readdir(oneDIR)) != NULL) - { - if (onedirent->d_name[0] == '.') continue; - - d_namepath = apr_psprintf(pool, "%s/%s", dirname, onedirent->d_name); - if (stat(d_namepath, &statbuf) != 0) continue; - - if (S_ISDIR(statbuf.st_mode) && (recurse_level < GRST_RECURS_LIMIT)) - recurse4dirlist(d_namepath, dirs_time, fulluri, - fullurilen, encfulluri, enclen, - pool, body, recurse_level + 1); - else if ((strncmp(onedirent->d_name, encfulluri, enclen) == 0) && - (onedirent->d_name[strlen(onedirent->d_name) - 1] != '~')) - { - unencname = GRSThttpUrlDecode(onedirent->d_name); - - if (strncmp(unencname, fulluri, fullurilen) == 0) - { - - if (statbuf.st_mtime > *dirs_time) - *dirs_time = statbuf.st_mtime; - - localtime_r(&(statbuf.st_mtime), &mtime_tm); - strftime(modified, sizeof(modified), - "%R%e %b %y", - &mtime_tm); - - oneline = apr_psprintf(pool, - "" - "%s" - "%ld%s\n", - &unencname[fullurilen], statbuf.st_size, - statbuf.st_mtime, unencname, - statbuf.st_size, modified); - - *body = apr_pstrcat(pool, *body, oneline, NULL); - } - - free(unencname); /* libgridsite doesnt use pools */ - } - } - - closedir(oneDIR); -} - -static int mod_gridsite_dnlistsuri_dir_handler(request_rec *r, - mod_gridsite_cfg *conf) -/* - virtual DN-list file lister: make all DN lists on the dn-lists - path of this server appear to be in the dn-lists directory itself - (ie where they appear in the DN lists path doesnt matter, as long - as their name matches) -*/ -{ - int enclen, fullurilen, fd; - char *fulluri, *encfulluri, *dn_list_ptr, *dirname, *unencname, - *body, *oneline, *p, *s, - *head_formatted, *header_formatted, *footer_formatted, - *permstr = NULL; - struct stat statbuf; - size_t length; - time_t dirs_time = 0; - GRSTgaclPerm perm = GRST_PERM_NONE; - - if (r->notes != NULL) - permstr = (char *) apr_table_get(r->notes, "GRST_PERM"); - - if (permstr != NULL) sscanf(permstr, "%d", &perm); - - fulluri = apr_psprintf(r->pool, "https://%s%s", - ap_get_server_name(r), conf->dnlistsuri); - fullurilen = strlen(fulluri); - - encfulluri = GRSThttpUrlEncode(fulluri); - enclen = strlen(encfulluri); - - if (conf->dnlists != NULL) p = conf->dnlists; - else p = getenv("GRST_DN_LISTS"); - - if (p == NULL) p = GRST_DN_LISTS; - dn_list_ptr = apr_pstrdup(r->pool, p); - - head_formatted = apr_psprintf(r->pool, - "Directory listing %s\n", r->uri); - - if (conf->format) - { - /* **** try to find a header file in this or parent directories **** */ - - /* first make a buffer big enough to hold path names we want to try */ - fd = -1; - s = malloc(strlen(r->filename) + strlen(conf->headfile) + 1); - strcpy(s, r->filename); - - for (;;) - { - p = rindex(s, '/'); - if (p == NULL) break; /* failed to find one */ - p[1] = '\0'; - strcat(p, conf->headfile); - - fd = open(s, O_RDONLY); - if (fd != -1) break; /* found one */ - - *p = '\0'; - } - - free(s); - - if (fd == -1) /* not found, so set up to output sensible default */ - { - header_formatted = apr_pstrdup(r->pool, ""); - } - else /* found a header file, so set up head and body to surround it */ - { - fstat(fd, &statbuf); - header_formatted = apr_palloc(r->pool, statbuf.st_size + 1); - read(fd, header_formatted, statbuf.st_size); - header_formatted[statbuf.st_size] = '\0'; - close(fd); - } - } - else header_formatted = apr_pstrdup(r->pool, ""); - - body = apr_psprintf(r->pool, - "

Directory listing %s

\n", r->uri); - - if ((r->uri)[1] != '\0') - body = apr_pstrcat(r->pool, body, - "\n", - NULL); - - while ((dirname = strsep(&dn_list_ptr, ":")) != NULL) - recurse4dirlist(dirname, &dirs_time, fulluri, fullurilen, - encfulluri, enclen, r->pool, &body, 0); - - if ((stat(r->filename, &statbuf) == 0) && - S_ISDIR(statbuf.st_mode) && - GRSTgaclPermHasWrite(perm)) - { - oneline = apr_psprintf(r->pool, - "\n" - "" - "\n", - r->uri, conf->adminfile); - - body = apr_pstrcat(r->pool, body, oneline, NULL); - } - - body = apr_pstrcat(r->pool, body, "
[Parent directory]
\n", NULL); - - free(encfulluri); /* libgridsite doesnt use pools */ - - if (conf->format) - { - /* **** try to find a footer file in this or parent directories **** */ - - /* first make a buffer big enough to hold path names we want to try */ - fd = -1; - s = malloc(strlen(r->filename) + strlen(conf->footfile)); - strcpy(s, r->filename); - - for (;;) - { - p = rindex(s, '/'); - if (p == NULL) break; /* failed to find one */ - - p[1] = '\0'; - strcat(p, conf->footfile); - - fd = open(s, O_RDONLY); - if (fd != -1) break; /* found one */ - - *p = '\0'; - } - - free(s); - - if (fd == -1) /* failed to find a footer, so use standard default */ - { - footer_formatted = apr_pstrdup(r->pool, ""); - } - else /* found a footer, so set up to use it */ - { - fstat(fd, &statbuf); - footer_formatted = apr_palloc(r->pool, statbuf.st_size + 1); - read(fd, footer_formatted, statbuf.st_size); - footer_formatted[statbuf.st_size] = '\0'; - close(fd); - } - } - else footer_formatted = apr_pstrdup(r->pool, ""); - - /* **** can now calculate the Content-Length and output headers **** */ - - length = strlen(head_formatted) + strlen(header_formatted) + - strlen(body) + strlen(footer_formatted); - - ap_set_content_length(r, length); - r->mtime = apr_time_from_sec(dirs_time); - ap_set_last_modified(r); - ap_set_content_type(r, "text/html"); - - /* ** output the HTTP body (HTML Head+Body) ** */ - ap_rputs(head_formatted, r); - ap_rputs(header_formatted, r); - ap_rputs(body, r); - ap_rputs(footer_formatted, r); - - return OK; -} - -static char *recurse4file(char *dir, char *file, apr_pool_t *pool, - int recurse_level) -/* try to find file[] in dir[]. try subdirs if not found. - return full path to first found version or NULL on failure */ -{ - char *fullfilename, *fulldirname; - struct stat statbuf; - DIR *dirDIR; - struct dirent *file_ent; - - /* try to find in current directory */ - - fullfilename = apr_psprintf(pool, "%s/%s", dir, file); - - if (stat(fullfilename, &statbuf) == 0) return fullfilename; - - /* maybe search in subdirectories */ - - if (recurse_level >= GRST_RECURS_LIMIT) return NULL; - - dirDIR = opendir(dir); - - if (dirDIR == NULL) return NULL; - - while ((file_ent = readdir(dirDIR)) != NULL) - { - if (file_ent->d_name[0] == '.') continue; - - fulldirname = apr_psprintf(pool, "%s/%s", dir, file_ent->d_name); - if ((stat(fulldirname, &statbuf) == 0) && - S_ISDIR(statbuf.st_mode) && - ((fullfilename = recurse4file(fulldirname, file, - pool, recurse_level + 1)) != NULL)) - { - closedir(dirDIR); - return fullfilename; - } - } - - closedir(dirDIR); - - return NULL; -} - -static int mod_gridsite_dnlistsuri_handler(request_rec *r, - mod_gridsite_cfg *conf) -/* - virtual DN-list file generator -*/ -{ - int fd; - char *fulluri, *encfulluri, *dn_list_ptr, *filename, *dirname, *p, - *buf; - struct stat statbuf; - - /* *** check if a special ghost admin CGI *** */ - - if (conf->adminfile && conf->adminuri && - (strlen(r->filename) > strlen(conf->adminfile) + 1) && - (strcmp(&(r->filename[strlen(r->filename) - strlen(conf->adminfile)]), - conf->adminfile) == 0) && - (r->filename[strlen(r->filename)-strlen(conf->adminfile)-1] == '/') && - ((r->method_number == M_POST) || - (r->method_number == M_GET))) - { - ap_internal_redirect(conf->adminuri, r); - return OK; - } - - fulluri = apr_psprintf(r->pool, "https://%s%s", - ap_get_server_name(r), r->uri); - - encfulluri = GRSThttpUrlEncode(fulluri); - - if (conf->dnlists != NULL) p = conf->dnlists; - else p = getenv("GRST_DN_LISTS"); - - if (p == NULL) p = GRST_DN_LISTS; - dn_list_ptr = apr_pstrdup(r->pool, p); - - while ((dirname = strsep(&dn_list_ptr, ":")) != NULL) - { - filename = recurse4file(dirname, encfulluri, r->pool, 0); - - if (filename == NULL) continue; - - fd = open(filename, O_RDONLY); - - if (fd == -1) continue; - - fstat(fd, &statbuf); - ap_set_content_length(r, (apr_off_t) statbuf.st_size); - r->mtime = apr_time_from_sec(statbuf.st_mtime); - ap_set_content_type(r, "text/plain"); - ap_set_last_modified(r); - - buf = apr_palloc(r->pool, statbuf.st_size + 1); - read(fd, buf, statbuf.st_size); - buf[statbuf.st_size] = '\0'; - - ap_rputs(buf, r); - - close(fd); - - return OK; - } - - return HTTP_NOT_FOUND; -} - -static void *create_gridsite_dir_config(apr_pool_t *p, char *path) -{ - mod_gridsite_cfg *conf = apr_palloc(p, sizeof(*conf)); - - if (path == NULL) /* set up server defaults */ - { - conf->auth = 0; /* GridSiteAuth on/off */ - conf->envs = 1; /* GridSiteEnvs on/off */ - conf->format = 0; /* GridSiteHtmlFormat on/off */ - conf->indexes = 0; /* GridSiteIndexes on/off */ - conf->indexheader = NULL; /* GridSiteIndexHeader File-value */ - conf->gridsitelink = 1; /* GridSiteLink on/off */ - conf->adminfile = apr_pstrdup(p, GRST_ADMIN_FILE); - /* GridSiteAdminFile File-value */ - conf->adminuri = NULL; /* GridSiteAdminURI URI-value */ - conf->helpuri = NULL; /* GridSiteHelpURI URI-value */ - conf->dnlists = NULL; /* GridSiteDNlists Search-path */ - conf->dnlistsuri = NULL; /* GridSiteDNlistsURI URI-value */ - conf->adminlist = NULL; /* GridSiteAdminList URI-value */ - conf->gsiproxylimit = 1; /* GridSiteGSIProxyLimit number */ - conf->unzip = NULL; /* GridSiteUnzip file-path */ - - conf->methods = apr_pstrdup(p, " GET "); - /* GridSiteMethods methods */ - - conf->editable = apr_pstrdup(p, " txt shtml html htm css js php jsp "); - /* GridSiteEditable types */ - - conf->headfile = apr_pstrdup(p, GRST_HEADFILE); - conf->footfile = apr_pstrdup(p, GRST_FOOTFILE); - /* GridSiteHeadFile and GridSiteFootFile file name */ - - conf->downgrade = 0; /* GridSiteDowngrade on/off */ - conf->authcookiesdir = apr_pstrdup(p, "gridauthcookies"); - /* GridSiteAuthCookiesDir dir-path */ - conf->soap2cgi = 0; /* GridSiteSoap2cgi on/off */ - } - else - { - conf->auth = UNSET; /* GridSiteAuth on/off */ - conf->envs = UNSET; /* GridSiteEnvs on/off */ - conf->format = UNSET; /* GridSiteHtmlFormat on/off */ - conf->indexes = UNSET; /* GridSiteIndexes on/off */ - conf->indexheader = NULL; /* GridSiteIndexHeader File-value */ - conf->gridsitelink = UNSET; /* GridSiteLink on/off */ - conf->adminfile = NULL; /* GridSiteAdminFile File-value */ - conf->adminuri = NULL; /* GridSiteAdminURI URI-value */ - conf->helpuri = NULL; /* GridSiteHelpURI URI-value */ - conf->dnlists = NULL; /* GridSiteDNlists Search-path */ - conf->dnlistsuri = NULL; /* GridSiteDNlistsURI URI-value */ - conf->adminlist = NULL; /* GridSiteAdminList URI-value */ - conf->gsiproxylimit = UNSET; /* GridSiteGSIProxyLimit number */ - conf->unzip = NULL; /* GridSiteUnzip file-path */ - conf->methods = NULL; /* GridSiteMethods methods */ - conf->editable = NULL; /* GridSiteEditable types */ - conf->headfile = NULL; /* GridSiteHeadFile file name */ - conf->footfile = NULL; /* GridSiteFootFile file name */ - conf->downgrade = UNSET; /* GridSiteDowngrade on/off */ - conf->authcookiesdir= NULL; /* GridSiteAuthCookiesDir dir-path */ - conf->soap2cgi = UNSET; /* GridSiteSoap2cgi on/off */ - } - - return conf; -} - -static void *merge_gridsite_dir_config(apr_pool_t *p, void *vserver, - void *vdirect) -/* merge directory with server-wide directory configs */ -{ - mod_gridsite_cfg *conf, *server, *direct; - - server = (mod_gridsite_cfg *) vserver; - direct = (mod_gridsite_cfg *) vdirect; - conf = apr_palloc(p, sizeof(*conf)); - - if (direct->auth != UNSET) conf->auth = direct->auth; - else conf->auth = server->auth; - - if (direct->envs != UNSET) conf->envs = direct->envs; - else conf->envs = server->envs; - - if (direct->format != UNSET) conf->format = direct->format; - else conf->format = server->format; - - if (direct->indexes != UNSET) conf->indexes = direct->indexes; - else conf->indexes = server->indexes; - - if (direct->gridsitelink != UNSET) conf->gridsitelink=direct->gridsitelink; - else conf->gridsitelink=server->gridsitelink; - - if (direct->indexheader != NULL) conf->indexheader = direct->indexheader; - else conf->indexheader = server->indexheader; - - if (direct->adminfile != NULL) conf->adminfile = direct->adminfile; - else conf->adminfile = server->adminfile; - - if (direct->adminuri != NULL) conf->adminuri = direct->adminuri; - else conf->adminuri = server->adminuri; - - if (direct->helpuri != NULL) conf->helpuri = direct->helpuri; - else conf->helpuri = server->helpuri; - - if (direct->dnlists != NULL) conf->dnlists = direct->dnlists; - else conf->dnlists = server->dnlists; - - if (direct->dnlistsuri != NULL) conf->dnlistsuri = direct->dnlistsuri; - else conf->dnlistsuri = server->dnlistsuri; - - if (direct->adminlist != NULL) conf->adminlist = direct->adminlist; - else conf->adminlist = server->adminlist; - - if (direct->gsiproxylimit != UNSET) - conf->gsiproxylimit = direct->gsiproxylimit; - else conf->gsiproxylimit = server->gsiproxylimit; - - if (direct->unzip != NULL) conf->unzip = direct->unzip; - else conf->unzip = server->unzip; - - if (direct->methods != NULL) conf->methods = direct->methods; - else conf->methods = server->methods; - - if (direct->editable != NULL) conf->editable = direct->editable; - else conf->editable = server->editable; - - if (direct->headfile != NULL) conf->headfile = direct->headfile; - else conf->headfile = server->headfile; - - if (direct->footfile != NULL) conf->footfile = direct->footfile; - else conf->footfile = server->footfile; - - if (direct->downgrade != UNSET) conf->downgrade = direct->downgrade; - else conf->downgrade = server->downgrade; - - if (direct->authcookiesdir != NULL) - conf->authcookiesdir = direct->authcookiesdir; - else conf->authcookiesdir = server->authcookiesdir; - - if (direct->soap2cgi != UNSET) conf->soap2cgi = direct->soap2cgi; - else conf->soap2cgi = server->soap2cgi; - - return conf; -} - -static const char *mod_gridsite_take1_cmds(cmd_parms *a, void *cfg, - const char *parm) -{ - int n; - char *p; - - if (strcasecmp(a->cmd->name, "GridSiteAdminFile") == 0) - { - if (index(parm, '/') != NULL) - return "/ not permitted in GridSiteAdminFile"; - - ((mod_gridsite_cfg *) cfg)->adminfile = - apr_pstrdup(a->pool, parm); - } - else if (strcasecmp(a->cmd->name, "GridSiteAdminURI") == 0) - { - if (*parm != '/') return "GridSiteAdminURI must begin with /"; - - ((mod_gridsite_cfg *) cfg)->adminuri = - apr_pstrdup(a->pool, parm); - } - else if (strcasecmp(a->cmd->name, "GridSiteHelpURI") == 0) - { - if (*parm != '/') return "GridSiteHelpURI must begin with /"; - - ((mod_gridsite_cfg *) cfg)->helpuri = - apr_pstrdup(a->pool, parm); - } - else if (strcasecmp(a->cmd->name, "GridSiteDNlists") == 0) - { - ((mod_gridsite_cfg *) cfg)->dnlists = - apr_pstrdup(a->pool, parm); - } - else if (strcasecmp(a->cmd->name, "GridSiteDNlistsURI") == 0) - { - if (*parm != '/') return "GridSiteDNlistsURI must begin with /"; - - if ((*parm != '\0') && (parm[strlen(parm) - 1] == '/')) - ((mod_gridsite_cfg *) cfg)->dnlistsuri = - apr_pstrdup(a->pool, parm); - else - ((mod_gridsite_cfg *) cfg)->dnlistsuri = - apr_pstrcat(a->pool, parm, "/", NULL); - } - else if (strcasecmp(a->cmd->name, "GridSiteAdminList") == 0) - { - ((mod_gridsite_cfg *) cfg)->adminlist = - apr_pstrdup(a->pool, parm); - } - else if (strcasecmp(a->cmd->name, "GridSiteGSIProxyLimit") == 0) - { - n = -1; - - if ((sscanf(parm, "%d", &n) == 1) && (n >= 0)) - ((mod_gridsite_cfg *) cfg)->gsiproxylimit = n; - else return "GridSiteGSIProxyLimit must be a number >= 0"; - } - else if (strcasecmp(a->cmd->name, "GridSiteUnzip") == 0) - { - if (*parm != '/') return "GridSiteUnzip must begin with /"; - - ((mod_gridsite_cfg *) cfg)->unzip = - apr_pstrdup(a->pool, parm); - } - else if (strcasecmp(a->cmd->name, "GridSiteMethods") == 0) - { - ((mod_gridsite_cfg *) cfg)->methods = - apr_psprintf(a->pool, " %s ", parm); - - for (p = ((mod_gridsite_cfg *) cfg)->methods; - *p != '\0'; - ++p) if (*p == '\t') *p = ' '; - } - else if (strcasecmp(a->cmd->name, "GridSiteEditable") == 0) - { - ((mod_gridsite_cfg *) cfg)->editable = - apr_psprintf(a->pool, " %s ", parm); - - for (p = ((mod_gridsite_cfg *) cfg)->editable; - *p != '\0'; - ++p) if (*p == '\t') *p = ' '; - } - else if (strcasecmp(a->cmd->name, "GridSiteHeadFile") == 0) - { - ((mod_gridsite_cfg *) cfg)->headfile = - apr_pstrdup(a->pool, parm); - } - else if (strcasecmp(a->cmd->name, "GridSiteFootFile") == 0) - { - ((mod_gridsite_cfg *) cfg)->footfile = - apr_pstrdup(a->pool, parm); - } - else if (strcasecmp(a->cmd->name, "GridSiteIndexHeader") == 0) - { - if (index(parm, '/') != NULL) - return "/ not permitted in GridSiteIndexHeader"; - - ((mod_gridsite_cfg *) cfg)->indexheader = - apr_pstrdup(a->pool, parm); - } - else if (strcasecmp(a->cmd->name, "GridSiteAuthCookiesDir") == 0) - { - if (index(parm, '/') != NULL) - return "/ not permitted in GridSiteAuthCookiesDir"; - - ((mod_gridsite_cfg *) cfg)->authcookiesdir = - apr_pstrdup(a->pool, parm); - } - - return NULL; -} - -static const char *mod_gridsite_flag_cmds(cmd_parms *a, void *cfg, - int flag) -{ - if (strcasecmp(a->cmd->name, "GridSiteAuth") == 0) - { - ((mod_gridsite_cfg *) cfg)->auth = flag; - } - else if (strcasecmp(a->cmd->name, "GridSiteEnvs") == 0) - { - ((mod_gridsite_cfg *) cfg)->envs = flag; - } - else if (strcasecmp(a->cmd->name, "GridSiteHtmlFormat") == 0) - { - ((mod_gridsite_cfg *) cfg)->format = flag; - } - else if (strcasecmp(a->cmd->name, "GridSiteIndexes") == 0) - { - ((mod_gridsite_cfg *) cfg)->indexes = flag; - } - else if (strcasecmp(a->cmd->name, "GridSiteLink") == 0) - { - ((mod_gridsite_cfg *) cfg)->gridsitelink = flag; - } - else if (strcasecmp(a->cmd->name, "GridSiteDowngrade") == 0) - { -// TODO: return error if try this on non-HTTPS virtual server - - ((mod_gridsite_cfg *) cfg)->downgrade = flag; - } - else if (strcasecmp(a->cmd->name, "GridSiteSoap2cgi") == 0) - { - ((mod_gridsite_cfg *) cfg)->soap2cgi = flag; - } - - return NULL; -} - -static const command_rec mod_gridsite_cmds[] = -{ -// TODO: need to check and document valid contexts for each command! - - AP_INIT_FLAG("GridSiteAuth", mod_gridsite_flag_cmds, - NULL, OR_FILEINFO, "on or off"), - AP_INIT_FLAG("GridSiteEnvs", mod_gridsite_flag_cmds, - NULL, OR_FILEINFO, "on or off"), - AP_INIT_FLAG("GridSiteHtmlFormat", mod_gridsite_flag_cmds, - NULL, OR_FILEINFO, "on or off"), - AP_INIT_FLAG("GridSiteIndexes", mod_gridsite_flag_cmds, - NULL, OR_FILEINFO, "on or off"), - AP_INIT_FLAG("GridSiteLink", mod_gridsite_flag_cmds, - NULL, OR_FILEINFO, "on or off"), - - AP_INIT_TAKE1("GridSiteAdminFile", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "Ghost per-directory admin CGI"), - AP_INIT_TAKE1("GridSiteAdminURI", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "URI of real gridsite-admin.cgi"), - AP_INIT_TAKE1("GridSiteHelpURI", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "URI of Website Help pages"), - AP_INIT_TAKE1("GridSiteDNlists", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "DN Lists directories search path"), - AP_INIT_TAKE1("GridSiteDNlistsURI", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "URI of published DN lists"), - AP_INIT_TAKE1("GridSiteAdminList", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "URI of admin DN List"), - AP_INIT_TAKE1("GridSiteGSIProxyLimit", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "Max level of GSI proxy validity"), - AP_INIT_TAKE1("GridSiteUnzip", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "Absolute path to unzip command"), - - AP_INIT_RAW_ARGS("GridSiteMethods", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "permitted HTTP methods"), - AP_INIT_RAW_ARGS("GridSiteEditable", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "editable file extensions"), - AP_INIT_TAKE1("GridSiteHeadFile", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "filename of HTML header"), - AP_INIT_TAKE1("GridSiteFootFile", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "filename of HTML footer"), - AP_INIT_TAKE1("GridSiteIndexHeader", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "filename of directory header"), - - AP_INIT_FLAG("GridSiteDowngrade", mod_gridsite_flag_cmds, - NULL, OR_FILEINFO, "on or off"), - AP_INIT_TAKE1("GridSiteAuthCookiesDir", mod_gridsite_take1_cmds, - NULL, OR_FILEINFO, "directory with Grid Auth Cookies"), - - AP_INIT_FLAG("GridSiteSoap2cgi", mod_gridsite_flag_cmds, - NULL, OR_FILEINFO, "on or off"), - {NULL} -}; - -static int mod_gridsite_first_fixups(request_rec *r) -{ - mod_gridsite_cfg *conf; - - if (r->finfo.filetype != APR_DIR) return DECLINED; - - conf = (mod_gridsite_cfg *) - ap_get_module_config(r->per_dir_config, &gridsite_module); - - /* we handle DN Lists as regular files, even if they also match - directory names */ - - if ((conf != NULL) && - (conf->dnlistsuri != NULL) && - (strncmp(r->uri, conf->dnlistsuri, strlen(conf->dnlistsuri)) == 0) && - (strcmp(r->uri, conf->dnlistsuri) != 0)) - { - r->finfo.filetype = APR_REG; - } - - return DECLINED; -} - -static int mod_gridsite_perm_handler(request_rec *r) -/* - Do authentication/authorization here rather than in the normal module - auth functions since the results of mod_ssl are available. - - We also publish environment variables here if requested by GridSiteEnv. -*/ -{ - int retcode = DECLINED, i, n; - char *dn, *p, envname[14], *grst_cred_0 = NULL, *dir_path, - *remotehost, s[99], *grst_cred_i, *file, *cookies, - *gridauthonetime, *cookiefile, oneline[1025], *key_i; - const char *content_type; - time_t now, notbefore, notafter; - apr_table_t *env; - apr_finfo_t cookiefile_info; - apr_file_t *fp; - GRSTgaclCred *cred = NULL, *cred_0 = NULL; - GRSTgaclUser *user = NULL; - GRSTgaclPerm perm = GRST_PERM_NONE; - GRSTgaclAcl *acl = NULL; - mod_gridsite_cfg *cfg; - - cfg = (mod_gridsite_cfg *) - ap_get_module_config(r->per_dir_config, &gridsite_module); - - if (cfg == NULL) return DECLINED; - - if ((cfg->auth == 0) && - (cfg->envs == 0)) - return DECLINED; /* if not turned on, look invisible */ - - env = r->subprocess_env; - - if ((p = (char *) apr_table_get(r->headers_in, "Cookie")) != NULL) - { - cookies = apr_pstrcat(r->pool, " ", p, NULL); - gridauthonetime = strstr(cookies, " GRID_AUTH_ONETIME="); - - if (gridauthonetime != NULL) - { - for (p = &gridauthonetime[19]; (*p != '\0') && (*p != ';'); ++p) - if (!isalnum(*p)) *p = '_'; - - cookiefile = apr_psprintf(r->pool, "%s/%s", - ap_server_root_relative(r->pool, - cfg->authcookiesdir), - &gridauthonetime[19]); - - if ((apr_stat(&cookiefile_info , cookiefile, - APR_FINFO_TYPE, r->pool) == APR_SUCCESS) && - (cookiefile_info.filetype == APR_REG) && - (apr_file_open(&fp, cookiefile, APR_READ, 0, r->pool) - == APR_SUCCESS)) - { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "Open Grid Auth Cookie file %s", cookiefile); - - while (apr_file_gets(oneline, - sizeof(oneline), fp) == APR_SUCCESS) - { - p = index(oneline, '\n'); - if (p != NULL) *p = '\0'; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "%s: %s", cookiefile, oneline); - - if ((strncmp(oneline, "expires=", 8) == 0) && - (apr_time_from_sec(atoll(&oneline[8])) < - apr_time_now())) - break; - else if ((strncmp(oneline, "domain=", 7) == 0) && - (strcmp(&oneline[7], r->hostname) != 0)) - break; /* exact needed in the version */ - else if ((strncmp(oneline, "path=", 5) == 0) && - (strcmp(&oneline[5], r->uri) != 0)) - break; - else if (strncmp(oneline, "onetime=yes", 11) == 0) - apr_file_remove(cookiefile, r->pool); - else if (strncmp(oneline, "GRST_CRED_", 10) == 0) - { - grst_cred_i = index(oneline, '='); - if (grst_cred_i == NULL) continue; - *grst_cred_i = '\0'; - ++grst_cred_i; - - i = atoi(&oneline[10]); - cred = GRSTx509CompactToCred(grst_cred_i); - - if (cred == NULL) continue; - - if ((i == 0) && (user == NULL)) - { - if (GRSTgaclCredGetDelegation(cred) - <= ((mod_gridsite_cfg *) cfg)->gsiproxylimit) - { - user = GRSTgaclUserNew(cred); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, - 0, r->server, - "Using identity %s from " - "GRID_AUTH_ONETIME", - grst_cred_i); - - if (((mod_gridsite_cfg *) cfg)->envs) - apr_table_setn(env, oneline, grst_cred_i); - } - } - else if ((i > 0) && (user != NULL)) - { - GRSTgaclUserAddCred(user, cred); - - if (((mod_gridsite_cfg *) cfg)->envs) - apr_table_set(env,oneline,grst_cred_i); - } - } - } - - apr_file_close(fp); - } - } - } - - /* do we need/have per-connection (SSL) cred variable(s)? */ - - if ((user == NULL) && - (r->connection->notes != NULL) && - ((grst_cred_0 = (char *) - apr_table_get(r->connection->notes, "GRST_CRED_0")) != NULL)) - { - if (((mod_gridsite_cfg *) cfg)->envs) - apr_table_setn(env, "GRST_CRED_0", grst_cred_0); - - cred_0 = GRSTx509CompactToCred(grst_cred_0); - if ((cred_0 != NULL) && - (GRSTgaclCredGetDelegation(cred_0) - <= ((mod_gridsite_cfg *) cfg)->gsiproxylimit)) - { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, r->server, - "Using identity %s from SSL/TLS", grst_cred_0); - - user = GRSTgaclUserNew(cred_0); - - /* check for VOMS GRST_CRED_i too */ - - for (i=1; ; ++i) - { - snprintf(envname, sizeof(envname), "GRST_CRED_%d", i); - if (grst_cred_i = (char *) - apr_table_get(r->connection->notes,envname)) - { - if (((mod_gridsite_cfg *) cfg)->envs) - apr_table_setn(env, - apr_pstrdup(r->pool, envname), - grst_cred_i); - - if (cred = GRSTx509CompactToCred(grst_cred_i)) - GRSTgaclUserAddCred(user, cred); - } - else break; /* GRST_CRED_i are numbered consecutively */ - } - } - } - - if ((user != NULL) && ((mod_gridsite_cfg *) cfg)->dnlists) - GRSTgaclUserSetDNlists(user, ((mod_gridsite_cfg *) cfg)->dnlists); - - /* this checks for NULL arguments itself */ - if (GRSTgaclDNlistHasUser(((mod_gridsite_cfg *) cfg)->adminlist, user)) - perm = GRST_PERM_ALL; - else - { - remotehost = (char *) ap_get_remote_host(r->connection, - r->per_dir_config, REMOTE_DOUBLE_REV, NULL); - if ((remotehost != NULL) && (*remotehost != '\0')) - { - cred = GRSTgaclCredNew("dns"); - GRSTgaclCredAddValue(cred, "hostname", remotehost); - - if (user == NULL) user = GRSTgaclUserNew(cred); - else GRSTgaclUserAddCred(user, cred); - } - - acl = GRSTgaclAclLoadforFile(r->filename); - if (acl != NULL) perm = GRSTgaclAclTestUser(acl, user); - } - - apr_table_setn(r->notes, "GRST_PERM", apr_psprintf(r->pool, "%d", perm)); - - if (((mod_gridsite_cfg *) cfg)->envs) - { - apr_table_setn(env, "GRST_PERM", apr_psprintf(r->pool, "%d", perm)); - - if (((dir_path = apr_pstrdup(r->pool, r->filename)) != NULL) && - ((p = rindex(dir_path, '/')) != NULL)) - { - *p = '\0'; - apr_table_setn(env, "GRST_DIR_PATH", dir_path); - } - - if (((mod_gridsite_cfg *) cfg)->helpuri != NULL) - apr_table_setn(env, "GRST_HELP_URI", - ((mod_gridsite_cfg *) cfg)->helpuri); - - if (((mod_gridsite_cfg *) cfg)->adminfile != NULL) - apr_table_setn(env, "GRST_ADMIN_FILE", - ((mod_gridsite_cfg *) cfg)->adminfile); - - if (((mod_gridsite_cfg *) cfg)->editable != NULL) - apr_table_setn(env, "GRST_EDITABLE", - ((mod_gridsite_cfg *) cfg)->editable); - - if (((mod_gridsite_cfg *) cfg)->headfile != NULL) - apr_table_setn(env, "GRST_HEAD_FILE", - ((mod_gridsite_cfg *) cfg)->headfile); - - if (((mod_gridsite_cfg *) cfg)->footfile != NULL) - apr_table_setn(env, "GRST_FOOT_FILE", - ((mod_gridsite_cfg *) cfg)->footfile); - - if (((mod_gridsite_cfg *) cfg)->dnlists != NULL) - apr_table_setn(env, "GRST_DN_LISTS", - ((mod_gridsite_cfg *) cfg)->dnlists); - - if (((mod_gridsite_cfg *) cfg)->dnlistsuri != NULL) - apr_table_setn(env, "GRST_DN_LISTS_URI", - ((mod_gridsite_cfg *) cfg)->dnlistsuri); - - if (((mod_gridsite_cfg *) cfg)->adminlist != NULL) - apr_table_setn(env, "GRST_ADMIN_LIST", - ((mod_gridsite_cfg *) cfg)->adminlist); - - apr_table_setn(env, "GRST_GSIPROXY_LIMIT", - apr_psprintf(r->pool, "%d", - ((mod_gridsite_cfg *)cfg)->gsiproxylimit)); - - if (((mod_gridsite_cfg *) cfg)->unzip != NULL) - apr_table_setn(env, "GRST_UNZIP", - ((mod_gridsite_cfg *) cfg)->unzip); - - if (!(((mod_gridsite_cfg *) cfg)->gridsitelink)) - apr_table_setn(env, "GRST_NO_LINK", "1"); - } - - if (((mod_gridsite_cfg *) cfg)->auth) - { - /* *** Check HTTP method to decide which perm bits to check *** */ - - if (r->filename != NULL) - { - file = rindex(r->filename, '/'); - if (file != NULL) ++file; - else file = r->filename; - } - else file = NULL; - - content_type = r->content_type; - if ((content_type != NULL) && - (strcmp(content_type, DIR_MAGIC_TYPE) == 0) && - (((mod_gridsite_cfg *) cfg)->dnlistsuri != NULL) && - (strncmp(r->uri, - ((mod_gridsite_cfg *) cfg)->dnlistsuri, - strlen(((mod_gridsite_cfg *) cfg)->dnlistsuri)) == 0) && - (strlen(r->uri) > strlen(((mod_gridsite_cfg *) cfg)->dnlistsuri))) - content_type = "text/html"; - - if ( GRSTgaclPermHasNone(perm) || - - /* first two M_GET conditions make the subtle distinction - between .../ that maps to .../index.html (governed by - Read perm) or to dir list (governed by List perm); - third M_GET condition deals with typeless CGI requests */ - - ((r->method_number == M_GET) && - !GRSTgaclPermHasRead(perm) && - (content_type != NULL) && - (strcmp(content_type, DIR_MAGIC_TYPE) != 0)) || - - ((r->method_number == M_GET) && - !GRSTgaclPermHasList(perm) && - (content_type != NULL) && - (strcmp(content_type, DIR_MAGIC_TYPE) == 0)) || - - ((r->method_number == M_GET) && - !GRSTgaclPermHasRead(perm) && - (content_type == NULL)) || - - ((r->method_number == M_POST) && !GRSTgaclPermHasRead(perm) ) || - - (((r->method_number == M_PUT) || (r->method_number == M_DELETE)) && - !GRSTgaclPermHasWrite(perm) && - ((file == NULL) || (strcmp(file, GRST_ACL_FILE) != 0)) ) || - - (((r->method_number == M_PUT) || (r->method_number == M_DELETE)) && - !GRSTgaclPermHasAdmin(perm) && - (file != NULL) && - (strcmp(file, GRST_ACL_FILE) == 0) ) ) retcode = HTTP_FORBIDDEN; - } - - return retcode; -} - -int GRST_X509_check_issued_wrapper(X509_STORE_CTX *ctx,X509 *x,X509 *issuer) -/* We change the default callback to use our wrapper and discard errors - due to GSI proxy chains (ie where users certs act as CAs) */ -{ - int ret; - ret = X509_check_issued(issuer, x); - if (ret == X509_V_OK) - return 1; - - /* Non self-signed certs without signing are ok if they passed - the other checks inside X509_check_issued. Is this enough? */ - if ((ret == X509_V_ERR_KEYUSAGE_NO_CERTSIGN) && - (X509_NAME_cmp(X509_get_subject_name(issuer), - X509_get_subject_name(x)) != 0)) return 1; - - /* If we haven't asked for issuer errors don't set ctx */ - if (!(ctx->flags & X509_V_FLAG_CB_ISSUER_CHECK)) return 0; - - ctx->error = ret; - ctx->current_cert = x; - ctx->current_issuer = issuer; - return ctx->verify_cb(0, ctx); -} - -/* Later OpenSSL versions add a second pointer ... */ -int GRST_verify_cert_wrapper(X509_STORE_CTX *ctx, void *p) - -/* Earlier ones have a single argument ... */ -// int GRST_verify_cert_wrapper(X509_STORE_CTX *ctx) - -/* Before 0.9.7 we cannot change the check_issued callback directly in - the X509_STORE, so we must insert it in another callback that gets - called early enough */ -{ - ctx->check_issued = GRST_X509_check_issued_wrapper; - - return X509_verify_cert(ctx); -} - -int GRST_callback_SSLVerify_wrapper(int ok, X509_STORE_CTX *ctx) -{ - SSL *ssl = (SSL *) X509_STORE_CTX_get_app_data(ctx); - conn_rec *conn = (conn_rec *) SSL_get_app_data(ssl); - server_rec *s = conn->base_server; - SSLConnRec *sslconn = - (SSLConnRec *) ap_get_module_config(conn->conn_config, &ssl_module); - int errnum = X509_STORE_CTX_get_error(ctx); - int errdepth = X509_STORE_CTX_get_error_depth(ctx); - int returned_ok; - int first_non_ca; - - /* - * GSI Proxy user-cert-as-CA handling: - * we skip Invalid CA errors at this stage, since we will check this - * again at errdepth=0 for the full chain using GRSTx509CheckChain - */ - if (errnum == X509_V_ERR_INVALID_CA) - { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "Skip Invalid CA error in case a GSI Proxy"); - - sslconn->verify_error = NULL; - ok = TRUE; - errnum = X509_V_OK; - X509_STORE_CTX_set_error(ctx, errnum); - } - - /* - * New style GSI Proxy handling, with critical ProxyCertInfo - * extension: we use GRSTx509KnownCriticalExts() to check this - */ -#ifndef X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION -#define X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION 34 -#endif - if (errnum == X509_V_ERR_UNHANDLED_CRITICAL_EXTENSION) - { - if (GRSTx509KnownCriticalExts(X509_STORE_CTX_get_current_cert(ctx)) - == GRST_RET_OK) - { - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "GRSTx509KnownCriticalExts() accepts previously " - "Unhandled Critical Extension (GSI Proxy?)"); - - sslconn->verify_error = NULL; - ok = TRUE; - errnum = X509_V_OK; - X509_STORE_CTX_set_error(ctx, errnum); - } - } - - returned_ok = ssl_callback_SSLVerify(ok, ctx); - - /* in case ssl_callback_SSLVerify changed it */ - errnum = X509_STORE_CTX_get_error(ctx); - - if ((errdepth == 0) && (errnum == X509_V_OK)) - /* - * We've now got the last certificate - the identity being used for - * this connection. At this point we check the whole chain for valid - * CAs or, failing that, GSI-proxy validity using GRSTx509CheckChain. - */ - { - errnum = GRSTx509CheckChain(&first_non_ca, ctx); - - if (errnum != X509_V_OK) - { - ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, - "Invalid certificate chain reported by " - "GRSTx509CheckChain()"); - - sslconn->verify_error = X509_verify_cert_error_string(errnum); - ok = FALSE; - } - else - { - int i, lastcred; - STACK_OF(X509) *peer_certs; - const int maxcreds = 99; - const size_t credlen = 1024; - char creds[maxcreds][credlen+1], envname[14]; - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, "Valid certificate" - " chain reported by GRSTx509CheckChain()"); - - /* - * Always put result of GRSTx509CompactCreds() into environment - */ - if (peer_certs = (STACK_OF(X509) *) X509_STORE_CTX_get_chain(ctx)) - { - if (GRSTx509CompactCreds(&lastcred, maxcreds, credlen, - (char *) creds, peer_certs, GRST_VOMS_DIR) == GRST_RET_OK) - { - for (i=0; i <= lastcred; ++i) - { - apr_table_setn(conn->notes, - apr_psprintf(conn->pool, "GRST_CRED_%d", i), - apr_pstrdup(conn->pool, creds[i])); - - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, - "store GRST_CRED_%d=%s", i, creds[i]); - } - } - /* free remaining dup'd certs? */ - } - } - } - - return returned_ok; -} - -static int mod_gridsite_server_post_config(apr_pool_t *pPool, - apr_pool_t *pLog, apr_pool_t *pTemp, server_rec *main_server) -{ - SSL_CTX *ctx; - SSLSrvConfigRec *sc; - server_rec *this_server; - - ap_add_version_component(pPool, - apr_psprintf(pPool, "mod_gridsite/%s", VERSION)); - - for (this_server = main_server; - this_server != NULL; - this_server = this_server->next) - { - sc = ap_get_module_config(this_server->module_config, &ssl_module); - - if ((sc != NULL) && - (sc->enabled) && - (sc->server != NULL) && - (sc->server->ssl_ctx != NULL)) - { - ctx = sc->server->ssl_ctx; - - /* in 0.9.7 we could set the issuer-checking callback directly */ -// ctx->cert_store->check_issued = GRST_X509_check_issued_wrapper; - - /* but in case 0.9.6 we do it indirectly with another wrapper */ - SSL_CTX_set_cert_verify_callback(ctx, - GRST_verify_cert_wrapper, - (void *) NULL); - - /* whatever version, we can set the SSLVerify wrapper properly */ - SSL_CTX_set_verify(ctx, ctx->verify_mode, - GRST_callback_SSLVerify_wrapper); - - if (main_server->loglevel >= APLOG_DEBUG) - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, main_server, - "Set mod_ssl verify callbacks to GridSite wrappers"); - } - } - - return OK; -} - -static void mod_gridsite_child_init(apr_pool_t *pPool, server_rec *pServer) -{ - GRSTgaclInit(); -} - -static int mod_gridsite_handler(request_rec *r) -{ - mod_gridsite_cfg *conf; - - conf = (mod_gridsite_cfg *) - ap_get_module_config(r->per_dir_config, &gridsite_module); - - if ((conf->dnlistsuri != NULL) && - (strncmp(r->uri, conf->dnlistsuri, strlen(conf->dnlistsuri)) == 0)) - { - if (strcmp(r->uri, conf->dnlistsuri) == 0) - return mod_gridsite_dnlistsuri_dir_handler(r, conf); - - return mod_gridsite_dnlistsuri_handler(r, conf); - } - - if (strcmp(r->handler, DIR_MAGIC_TYPE) == 0) - return mod_gridsite_dir_handler(r, conf); - - return mod_gridsite_nondir_handler(r, conf); -} - -static void register_hooks(apr_pool_t *p) -{ - /* set up the Soap2cgi input and output filters */ - - ap_hook_insert_filter(mod_gridsite_soap2cgi_insert, NULL, NULL, - APR_HOOK_MIDDLE); - - ap_register_output_filter(Soap2cgiFilterName, mod_gridsite_soap2cgi_out, - NULL, AP_FTYPE_RESOURCE); - -// ap_register_input_filter(Soap2cgiFilterName, mod_gridsite_soap2cgi_in, -// NULL, AP_FTYPE_RESOURCE); - - /* config and handler stuff */ - - ap_hook_post_config(mod_gridsite_server_post_config, NULL, NULL, - APR_HOOK_LAST); - ap_hook_child_init(mod_gridsite_child_init, NULL, NULL, APR_HOOK_MIDDLE); - - ap_hook_fixups(mod_gridsite_first_fixups,NULL,NULL,APR_HOOK_FIRST); - - ap_hook_fixups(mod_gridsite_perm_handler,NULL,NULL,APR_HOOK_REALLY_LAST); - - ap_hook_handler(mod_gridsite_handler, NULL, NULL, APR_HOOK_FIRST); -} - -module AP_MODULE_DECLARE_DATA gridsite_module = -{ - STANDARD20_MODULE_STUFF, - create_gridsite_dir_config, /* dir config creater */ - merge_gridsite_dir_config, /* dir merger */ - NULL, /* server config */ - NULL, /* merge server config */ - mod_gridsite_cmds, /* command apr_table_t */ - register_hooks /* register hooks */ -}; diff --git a/org.gridsite.core/src/mod_ssl-private.h b/org.gridsite.core/src/mod_ssl-private.h deleted file mode 100644 index 7b0b784..0000000 --- a/org.gridsite.core/src/mod_ssl-private.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - Copyright (c) 2003-4, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/* - - Portions of this code are derived from Apache mod_ssl, and are covered - by the Apache Software License: - - * Copyright 2001-2004 The Apache Software Foundation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/*------------------------------------------------------------------* - * This program is part of GridSite: http://www.gridsite.org/ * - *------------------------------------------------------------------*/ - - -/* - * After 2.0.49, Apache mod_ssl has most of the mod_ssl structures defined - * in ssl_private.h, which is not installed along with httpd-devel (eg in - * the FC2 RPM.) This include file provides SIMPLIFIED structures for use - * by mod_gridsite: for example, pointers to unused structures are replaced - * by void * and some of the structures are truncated when only the early - * members are used. - * - * CLEARLY, THIS WILL BREAK IF THERE ARE MAJOR CHANGES TO ssl_private.h!!! - */ - -#include - -typedef enum { - SSL_SHUTDOWN_TYPE_UNSET, - SSL_SHUTDOWN_TYPE_STANDARD, - SSL_SHUTDOWN_TYPE_UNCLEAN, - SSL_SHUTDOWN_TYPE_ACCURATE -} ssl_shutdown_type_e; - -typedef struct { - SSL *ssl; - const char *client_dn; - X509 *client_cert; - ssl_shutdown_type_e shutdown_type; - const char *verify_info; - const char *verify_error; - int verify_depth; - int is_proxy; - int disabled; - int non_ssl_request; -} SSLConnRec; - -typedef struct { - void *sc; /* pointer back to server config */ - SSL_CTX *ssl_ctx; -} modssl_ctx_t; - -typedef struct { - void *mc; - unsigned int enabled; - unsigned int proxy_enabled; - const char *vhost_id; - int vhost_id_len; - int session_cache_timeout; - modssl_ctx_t *server; - modssl_ctx_t *proxy; -} SSLSrvConfigRec; - -extern module AP_MODULE_DECLARE_DATA ssl_module; diff --git a/org.gridsite.core/src/proxyput-example.c b/org.gridsite.core/src/proxyput-example.c deleted file mode 100644 index f0fe834..0000000 --- a/org.gridsite.core/src/proxyput-example.c +++ /dev/null @@ -1,131 +0,0 @@ -/* - Copyright (c) 2002-4, Andrew McNab, University of Manchester - All rights reserved. - - Redistribution and use in source and binary forms, with or - without modification, are permitted provided that the following - conditions are met: - - o Redistributions of source code must retain the above - copyright notice, this list of conditions and the following - disclaimer. - o Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND - CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, - INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED - TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - POSSIBILITY OF SUCH DAMAGE. -*/ - -/* - Change the hard-coded defaults below to your set up. -*/ - -#define LOCALPROXY "/tmp/x509up" -#define DELEGATIONURL "https://testing.hep.man.ac.uk/gridsite-delegation.cgi" -#define CAPATH "/etc/grid-security/certificates" -#define DELEGATIONID "1234567890" -#define EXPIREMINUTES 60 - -#ifndef VERSION -#define VERSION "0.0.0" -#endif - -#define _GNU_SOURCE - -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include "gridsite.h" - -#include "soapH.h" -#include "delegation.nsmap" - -int main(int argc, char *argv[]) -{ - char *reqtxt, *certtxt; - struct ns__putProxyResponse *unused; - struct soap soap_get, soap_put; - - ERR_load_crypto_strings (); - OpenSSL_add_all_algorithms(); - - soap_init(&soap_get); - - if (soap_ssl_client_context(&soap_get, - SOAP_SSL_DEFAULT, - LOCALPROXY, - "", - NULL, - CAPATH, - NULL)) - { - soap_print_fault(&soap_get, stderr); - return 1; - } - - soap_call_ns__getProxyReq(&soap_get, - DELEGATIONURL, /* HTTPS url of service */ - "", /* no password on proxy */ - DELEGATIONID, - &reqtxt); - - if (soap_get.error) - { - soap_print_fault(&soap_get, stderr); - return 1; - } - - if (GRSTx509MakeProxyCert(&certtxt, stderr, reqtxt, - LOCALPROXY, LOCALPROXY, EXPIREMINUTES) - != GRST_RET_OK) - { - return 1; - } - - soap_init(&soap_put); - - if (soap_ssl_client_context(&soap_put, - SOAP_SSL_DEFAULT, - LOCALPROXY, - "", - NULL, - CAPATH, - NULL)) - { - soap_print_fault(&soap_put, stderr); - return 1; - } - - soap_call_ns__putProxy(&soap_put, DELEGATIONURL, "", DELEGATIONID, - certtxt, unused); - if (soap_put.error) - { - soap_print_fault(&soap_put, stderr); - return 1; - } - - return 0; -} - diff --git a/org.gridsite.core/src/real-gridsite-admin.cgi b/org.gridsite.core/src/real-gridsite-admin.cgi deleted file mode 100644 index 74a00102428cd5c64342d721f34b0f96e422672f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 96256 zcmd4)3wTu3)d!3pLeK%DiHaJnw$X}$S5#CKFA*3;MH#s$UN9g84v|YFGm4i;a1tek zXslGJwTe|+ytL8^Ev-_cQbB8LR9d4=-$tA2o=$AXzIioOYQEoZt-a5j$whho&;NU# z4?Wql_Fil4wbxpE?aSHcoE6c@=MEY)$aDYlyultJ^Jso#4AQ5gS~kWj@pkh@dWU)6 zLh5-e8&d-uT+R5+YY47Ycov3ACEwY_=@eKUZdRQ0bO5(Z)7uy}fH4GR39gmCkPQ}%P>l9q!eFM_OT}W5s8jb4;n-@oV46cQ^F0y${E)D%&hTmsem^Pk< zYcj4YaV^2M0M`^;7vj1J*PXZ;a3yff#C0UDp}20r#eX;BS}ecxPdSnr3(rP+zWqHG zX&tU>aNU7xFI)%W;=jvr9gXWST(slCxaQzmfvX-D|Ev~)_;5q;o|5a$>U1rm7Aw2?DqlJ4XC-3HY z>%X5L`49!P_cS=|X28@h;WWy(17=?(yeF;tCVS$;3z z<$%*LCSmHFF&l}uxA#fUp{Rcq%Bdfg{~Y*h0n?`mKMr_3;1ezUCg9D08FyIzSHRl= z(_Byb0}y{2)I%h zi~lsrHv=AT;bTy~o#jZ$@7{d0A8>`0uL}4E@H~ru64GwK#kPDb=pqm0M`E`8AejKERgOp}zHi z&$IAN42KYW;jw>vG3-vDt{J&P-VbJp` zz|=F#4+Fdw@BD)Rc)l$k3D^L3{pn1=-GIAneHTEU$Pe=)9OEhfnShG{ z-(um_*Dz<1N>Eh z$5=S8mwmS&zxLPJ@#cQeuLb_EEdGAL-w^VL&rrS|_VPXe zJkqYssPDf49vgz!0-gl;I$M7|1Yv#P2^ zT$PRSW}ZCyw6crOxhPsTFHz~0O}rex&!6B`U0b#!vDk}V8Y^2o?__WM`BTa&6Y(mq zY~hlHaRKKqD=(KHbK}bv31aNR=;dW|s;U+)SdxX~H&!azlJXnK_4+xB66IR!g7SD- zRpOe8^11P{C36;+XNibgHXl`a=S;i!gtGH5o*q3fI<>5-Jnog9H+jnVb0(KfIrrRY z(dlK=&lx{CT9)Ovu&OFizD(Ik(^yIQ@_5jMgO;`k3%h9B= z1&fz1DXWUlSr#uVqjKghyRkC9w6}id%$rwMz9hcvMlTkZL#K4)H8Y}vx=k$EBV1RD*>ZF$xTOP7>m%^cDYgjb?z z)2B?0mQ9#G6P2J%%a$!&RyMD^GVW_JBq$TrJ9)~e#h|)Aiec%LSoGp)(%4W z!nI&2+T|~#ffo9!QV(vT(WRps7lCEnYf0{jZU3fR=I59 z5-VI)+5F1>B%kZgS-2$2;QI1q3+G$CL}yNiK<7`nSeiH&qAZ*{XOZGASR7xtxE!KZ zi2g;dIqH|DW|c%8i;|Q)mo=IMuL~Ixw(D&q=@ik6r%%1SY%Xe}wQnrD`22~=FE(Rp zY|6B#2#WkFao|Apw2;+GFR@rMH?eFPJgIDM`7&!;8c#Zu`1`c!Q_sKnys~+7;&Zez zwgq~sTDa6Ij$EpsxH*e1PAtBrd|4JPT0A##k(^f^pSpBuJi4fSF*L=@Y4K%q7gzGv#Y^XvqkO{BB@jW%Vsn;Nm7lwCQ8|mx zM}(4$WrQYB2bWsi0lu)jymI`aIZLjsnpi%6PGV710sU2lYAbK_ zs^asOCgR@wc}pwHmw3?C;-%M@dsR!s-{*UC;!78K&}jLR>%I9%tB69n%DIcEdlWCd z0cJu`0=;K3IvbiwAD*{xnKys_qC}PNRSIu-24f-m(Y*5IURC*$dGpz@`L-s?Gbc`Y z(23?RSv)5`*Y~RC&RIf6D8&E5m%o=#VRIH$`g5vaG%v9Pk>y$z%$-wJ&N2uff>e>g zd?gX)%QzT7Sa!Lk^XJXEkpMdGGLJIas>p$jo$JllRxZ94aTS>qqa0-zG3I(?v0yQx z>|727W!IFk<+$c7lKw10&*x8XzQk0od^tv#`J#(53_H@&vP4z+Jn&#}wvl=RE^7-Q@l%06o zNx`r1?-PPtj-+|=pQikaNlox?knEo-h{<;j?qFNSe5K(p{>#J8C`%PqI_4_9V(@Ri z#c_DKDKYp@bCp&n1dfwSDP>k_ZI9Nj7|LZ3q@rZ{&q+r*=IejD@2B`qVwUH7-^Sd7 z>kj_gci}=z$%c3bVLr&bs)H5|Wor(%@ZM5B*c)x(B7yU~(*g6}I?MrgyIa>5L$GM( zoNx#xMNOD{?hXOhFoo!AnL@w^nPRTAjw$4Lj49?y>zRV*(@e2S*}xQ%Y-BnNb1SBp zoIcOA0Q>GtA^BFOSafY?iUz#SbZ^gVVTy^@4yM=yX=OUx^V*p1=Xvc+_xHRGrdU)O zrkLz@GCdIc>P!#9UOrQ7-gGlP*zJZ4kPYcHugf8mST;;^c>8UnU2T)InxQSKhue@Khr4e&-7f_pXqt9 zKhsIDKhyJJf2J3}{!A}~{h3aN{h3|_`!l^5_GgMkNHfzI?9cQP*q`ZC*q`Y%*q`Zi z*qwh_BT#)C|4e(q^Im<~>p6K9dRWhh)%Xi7dp#oBQPV7kDlSBDg|aF@=FQN z7MKyqpF}t&Fe8&6BU~ylBa{yh^HQS)W~B0G6D|>$5zA+TQbhtYa`}~nJ%Jg){N;o* zUm{}!Bbi@AxLsgIG=CN07J(Vr{3gQ90yDz-YYA@J9gcET}%85#W+!leQ;Li(+QM+@ws$N24pO9aj*YzP+# z93h+`>MTDCLKA14Kc~ct%E+Je(c%8t9 z6CO#pN#K!$M-#3Q_!z=t30Dd{ns6!M*#eItJc)2j;IV{bgi8fJgD`Iwq(%!|N_aNm z5`iZY_6ZjWJc)26VNc-6gqIV}>}306glh=53p}0hD#9%S&m`PLxLM$<2(Kl)LEzbh z*AZSP@I1on2{#Gs6W&0$M&Lz+HxsTDxRP));n@Pm32!GH6L>k{7Q&?h-$J;R@MwW+ z2)7e15xADHAzUQzD#97Up1`XKcN5Nh!S**1#+(N27kCZf2;mli*Agxw+$`{ego_Dp z5O^Ko62j{QevI%)!c79NCp?;PjlfS6=Iw!0rNA2qmlB>W@J7Ou2*(88OgKikRN&_c zbNf6sTHt2Fvk8|7yp^y|xJcmbgewVq0>4gpIpNIb(*Ft95N;QE2jNwOTLf+;+(fup z;5Nc*32zX%o$xxs>jdr~yq<8Az=rS!!ZiYS65dR>Qs4~XX2P=t?jpRMa7^HC!YzbL z1>Q-xmGEeRJw$xJop6c3`GgJOB7q}>GlV^X3kY`;&iqIEKVi;^Q|$r|CmbQ%B5*O` zBEroAA56HI@CJcP2$v9EC-C8fM-pxlcqHM`glhyohVWRzl>&1l_Dc!R7I+NdNrYnp zk0l%Y@Zo-+*r2iAfiUjQ! zcnx9h3#VEHUQ3wU)v0EIA0%8%cmv=QKEAsC{bWZbHhro;?+TQR!JkVm_4iqyA2I(z z!0Bpg!dzrpj3bhF<;s_rV28dTc`*F1t~s99)6y_&=c_LZ4(2O0XFd(?USiZErMQ>d zP*nF;{DAsTlg;^$67G2`$WEkR8A8-SufAOWsm^sCslmVqo(FPlCG(_~2nyxE>?K0W3?Oq}Z+ zPJ#a{;S=Cq%80z%nRT&4k?OpwkTuR_6;ycUIE+XtJ*zK4IqUk-6S%(xiK+{{c(K%9 z;2&el?$omMz9cBMnF&Ww41%5n{vYnowq=)Fg8hZjaDSc6KgZD&d2uZ(^4o3M2wMjI z?KTTCFMy#TP+fE480vIi=1mLoD59#a6a{R+-!c8MDqUf--qNgBUzXLsT%ZcCk9H@kyS>Ej+oIj|5DE=p>HqvpM6Hiz8lsu{sA-5A zm1{rwH6pPa(pS7Q8>0plzb{lpX1$~8Y>0O5B2{-!qO&J~N;`TI?LCQ%eJhOs4k&nIoRVm+fa?8B@f zm)SAO4CY9-=flAJ%P;h!M1lOG(eu*Zkaiy|u2lrJNre;OyveO4w0?I;j=I2k1nbBg zIc6eMNdFwQ)!KSnw1cMH7JXimjZE0|p;x2nA9qR9>!a<=Dq+@pF3T|MG-hpcS)I&^ zF>9mC+L5g8^x_4{YU9OsOIGjj68jNpHj!5RpKwq8au^m!?_qVtk`GyuaOAHit6%pD zYyYJ}^(0<5+Y_Sa`e<{qx*0_~ti1mw-IexA--!pink3G1V6$?7&#_G@4_M%#KoA{cEZ?P|0b zYx`ilnu8I)DVP4K+|sKWqHU%1(T?;q>S7;=Z5IBowLwR+y2Fc~&Vs{O@J@Z82?ogy zf0VSc*_=pKGNekgHh(YMECe!A?(bM`O;&I95(s7m{sb2M_usZIDTwclX7(hu_9UJ+ zs~@sFk@38L36Wa_IX`Abt&=ju{DN)Kjo*R>QupHzxmFPI$BwJ$C@xLAo(22mwxG?w z3Ar>yr4}TspI7Oamw{^0s`}{jX_c#)a^0YPeb@9k;#Ce1SEu_jj)}0{5Z;2vMtJ`s+W3fcUD~Bzd**n`;nEs zn^`Y2YqQJBFl#%r9(P$StoRM7xZC_L<0?L^|B4GG@Rg)alo})cpDf{bzK-zQmXJqN zSmR$T;pJaP_zUbap{c26OZbr`EC~ol$Y7~D%H*hNG4{?#TWe`QwzM7pa?Ko=wraA{ zPO`NBXKB~(0_~C5J7c{Cme!k1N9{I?0@~%&!4S!AF`KkkqembFMf`nj_Cqc^F|d>i z$7@YL9D^YWU7+N_&o_9bsu7*#+7^O;Fk)mi81& zTfPglXJA{FGQWzsE0uDlr5&{kv=^M9w2hYb0!#bx$6w#xBd~4HdM~lGmsr}L?E>xf z*cvA7ewOxXOPkmQ+QVZ?`!44CZ0~$ad)hA0UV^P&*82lXTWM+k+xhkFeeQInonvWl zwzMw>v`0w@?8mPVP%$eWO~S3CQze!`tz}TNYYYaNe_?e&27hIWmfvL=oV{xd^2|>y zgNH1G2P}gx(?Rq5?H3#nZah+(e~qPm+|s_Z3$&-RcSG$*SlW%2_V!(%J(}?owEw^i znvMRArM+MmXiplhv_G}9zqhn|?E>v15v5&bY2UH5Z~f!zb@lO3r9H*ceq?Fy+XdQ< zdnoPaGSWxyC!6zP<}y`VeH3#Wj7ng&(Y&n#6B}A84c%x;H1G%xX15znp=NM8g_+{P<|f?8 zkQvs-Wc5Zbfte=O=pYuknsj!|-#v+ukQRbSU0m+=B#KOr>L|s%E>JesO+o{Jd$2i7 z_+p~?<>OL8Lv&Srbca;B(L8~>DN<=yvbxJlT+T{sT&3U8N`YG8NtLLqNW_WCWT6DQ z^WT>C9W2>*JSf~iAmAtkQ&&-@>WCKy0W`Ejc(D<_ca3e|2AN2fU;)_RVL6I*5p9;N z&UlF-spF-C$Rzs`N3g=qJjwP7v7xfFs=!}`ax?Ek_HMY)mU~4Fm|0y&Pk97|V$YG{i`s<_-=8@24fv?v?D+oy zixT!Mka_d0l7H>;`Z!pJbdEj_c0}Nj;$Yj=NV1FOc0vmLnP6}B`@XHNAZA8%NN~c! zt|3~ay2Ik1a|y8Mp=1qlOTrO? z&i0;0e!DF)wjXW0r(+&C`p;22e^3p>wVBn-tmj--2W|PfsK=Q1|KN)l{P#kC}mi3`H)KWZa zDX@kWiV>EgG@#&?9qTyCQmj;pG{Q*4Ki;D6-3R?7i$2w&A5HW#Ecyo@xaQ}j_o1q0 zqrj}zp&@;X*^0a2=%66cu5W&Pizou92n6PRiQaTdIGL%ugJtM$d)zKa^-->pC17-! z@2;?f7#Oz0&Rr5$`m^>=4TI=;x4^%PEqNvAsWJ1X zcH5mGl}P`BObUvU-Gf$43H77an0aMyC#=5?Y#O7;`>nbGhHC1*M4@ z^E*`$J+ZoL5O-}O7%e7&N5(wk$~tAI>l+-)Zlxcx@KBZRv}o4~YnyhqC}X4*X`k#8 zdoqU3Fbz`+>Wk8_tWbWmmq-sv?gw^mD@FIg{w#l6+*kp`(3WHdw8IhFORXIyZHsc( z3%+S1)wMy;h?$%JYE|1`q&iC_7U7D`g<>RF>%*i-X?F?5TE!ujBOOciA-GGsS)nR% zTPDG~qa@|zu(`;`kCEli`fqhO0i2i{g0cy;XW9q)AD?Fdas zfrm&dVRn>o!oUj-7&}`VF{hD%x1X-mi&2}|wlCYJffur`R1GLvKlEmfE>FY-umLx{ zpT0O-##k2u7K>3~T|N^d6Eq3HV%^i%NETEQGZ*|N+ZUlzSQjx?4T#}Rwk*TeHD+HK z0*bUZWUc$b-_^Q5fr%P0PQqgC&SKT=)b-WybP0D2n4yd|pJ>IH37m`!F+!WzF5~~( z+3r{!cN=D*M9sHC`+og|d?A9~+g0xmh*x)*R$13T3-F=!=-Xz%UezMQ z>_1Rz5e1EEb3Ka1qQB3-lhxlaSKQu@Nq(>Li)h8>y_F<`NfI^IBxn|N-p-NuSXC?h zNOm8g^L7`3+RVce(4h17oF27A*{7bC9u@I>pf`Wd1?X!tMM6~7pyJgv7uLZcV3}50 z2D|#$$h2lFnf2ih?uHWw0IOZS7l7m+CUq@bUUkBMB5lH)byWj4}o^oU|J2IE6*!>O? zy{1nsG7Cl5j+je?Y8R$Yt!9vf0PV$)>N#!9z$*DZw`8`Ke8u$X`#KG<9-h0e-a?5xa~bfw4?o|Ww|H}^r;S(!1^FZ zu=1VWKG11eWz>KVV9J9VcwrytG#AKjSsx!bP-{R9$1Hm>Ke4RxiXcb}iAH@M=GVA^G#SLJa{flU(nMu!`4y3BDByWtxh zIVStBj@hX>Qc=EJ&td}eO|>!D`^`|2OtlVKWhDS&hrjnio4uQ6_udJy1N`Hbk#3B{ zLK`FfOp92JE`K{@7-d%!kBpcG;ZxdcTV(wJV?l^b#vCo9EuwnFKO92qlwdcp8mw^O z4(c)=UIBrEDQu-^QwOAu?Bw&HJFE(@jTf|E^9G*lCG=##S2zeJpu8Pv9pttft%Dr0 zTx#pI-7II&xQX$(~2Ai zd{SbcIN;z4+iO}7CdK3te<NBN#|r(j-7j%9EOFT( zU%f)}2KLog<;J+1(O^Lx;rwzZP6;8ZBdqV_G!v7=?jFnmcgh@aXBx+Zx~+FRif(%* zNe&qa#ZFRm3q?06+*zfu+oE0MjkSC7jJk<@X$f|CJ6T&N76n~BV;p}1>Baoo;72nb3(n}_A#E932q027N|CFf{KZiTZP^Bel9aNF%PA1eI3 zMLIyg6%HA&!h9{kQ73HA=JoXSSoPsx4w{cMUZRrpSyunlCLA34$C0hPbP2RKE?SU4 zE4mRJ(g)yBO<22FT052gzswgSD-IPxQD&KhQ4L`c)3K830R)%CE+G(TfVLplPfHeu zSu8)=4Sa}2(v|3I)aElVv%y5 z)EB$d79E?#Zns$nwY z|Hk3UB084LmAMCtNetGH-wY5@X$JhzNsFWh7o~sCwl|_?^VfM|YjVLf=^kXsAKrr+ zTP{UHg}WicDaAUGcBFYD*tYavuvyP%v)XOe6WJ_p2~{!D+-I{m%fV48L^oSdoyD!O zSryr=cAIrsHmh{0a-5jWa%TAU?_IZ+Drzj|L0Qb7*epKI1XoXAD$ZW)Z?XCR(j{K9 zy2Oj)7N|}xFtx;pF%f_Lc8j-7@aWp2bpMP>73vvFj|Os2SuL{qbte{sn17kYO)75c zOR;&k7oTB;sj&#xWSRZaW=#pQpj6x!>Z!~(ZP{7hs}^mfW&J2wqe||#t1Mn1%Ul+` zZV5h<^$mQ1#E?Y(b5|LU$Ih*g$?g*nvKPQ?UpmBdxTw|h0 zRBU{WGATZCK_*jeeoXV(@#8p(hB%F-4Z`l|p2QgZ^=mBNNWp`9;taRV+Ru@~(S|q7 zfICFCm0|+|x75eyGa>SjWz=-BF|yhz${tY;4f1aQSLk;(l_)#Lp;aS@3 zFTcjtGfeA|@i+A?jN?KhuJ)Ei`AAoJtm;oTYlmj-s!n)}|EqN3RjI10mF++}xjHLI zFP)sS{i}7dzbpSroy@jkd@9Qq%n>msQJtXa+RKW~yIM$XI1ha#oAoox;#tj-zBp}V zCk9vgRAY24R%ye{HH+9IG50zvn9J+*`9#;Nu`n6`inM85v^752xi_NkF=patQa}ls zr8;D3btvt7iRaOc3Bh79%NI`vc zO+$1Irfh|^*myx(w7ZEs8}$S_%JoL{SV~qBr%8`7PwEPAK* z^O@K<4H?D;L_3yYZn_OR21l+4aKF(REMsQ8)YGH8B0aDacQ%2%a;)c-?shBAymRsB zrT(JXTo_@JJ1*LN>mgXTuJrgYm^7f96YD#j!@}}F8ywx)80)z++O;YVkKtfX3r|~} zmUl}dehrRBCKdh$jJgWzZi0F>t8vnoS;8;x9CUhKVck_yTF@{9XM;wyfTdU}gW!eU zq^)46pp6&?U2+jfL61G`Fj@D$-Hq3iSrVi#5LAYB&edx z?9O9JXqt$dtswn_q~H%utfAhtE)P5#>ms0tnNzi{nk@wPjGwIe;9apNPTYiLN3TYs z99>Vdt&fVz)|Wa8AgKLyXuE6AJU7QGtoxOyR9b*v$t|Mh!n!U>Pv&fBviZ!Ic{t2J z$fsOa#mrlQ_saI{UUHWc>a7>E8@U3?JS4|wrF{3 zsz``=Tc};D-Snog?j#he7SJKQ)ZxV5BA!!Ndo^c^Tf}(^S6w22G@CK0z!#@^Q9DlR zFr8T9nG6+Zp$Y^~_$HNFa6Q7Nmb~$Th)UQ0f|>-U5|o&+pWUr7Dg zz-z42!ux_k|8_FR17Eh}Kplp&Wa~m?Wmz)H+5z(p8Umgiw}z| z-J+Ghs^3$qkF&N-%r;MGZhf5rl-$CTyc{IZc)Ebz1O>^Ndn(ONrd88f@0K*S^ zeR7KgB;2RqC`Q%#&1jT4O2tV1-Fe7zWd7aN6lgQK6b_^-%GtnhO1{Zu=lAxF|2jjW zpN9y}cLZ>VQ1*$M-H$^QJA!^4;w%|P`*VnDSAWoigEhxZayLqYZHK|a>5=C}Pnh8p z1R*;weQ409fO4xtNgO07-1f{y^^(9|{!=$Xi5nE#p7GJA%(k%L{+xpNsk9YNFvQf3 zun(d&4Af@+=`1V6T;2WD&2L-M$3QYZm{n{RY;lsy!8eH(_o~&?c!;aGKH4Hx3^yN( zU1cWOV%imOGm^cPi>|w6CfR8k)j6nxR!GhpweLA80ktsW)gYs>&hL?-rqc}989qbL ze2gRwb<0sQf}b-u(<{a6GV5Z<6`?xKBp1eGz)5c5U)hq)%!P&0al5V;hh~{sZX
c9Yl`Gi%kkVY{ak?XfKH2Vc<6g1xT7 zy8A^&Mh+ejEjD}Go-a>>LPO>uQJJW--Q1&qQ|C+12`4$X$w0+>vS+!#>(psXg9^hw zE$5QWO`!}!{f_#TwQgbEZcZSXZAN^=y~HEB%qc3S zM5=64Ym_+kPm#R9Z)aZ`r;>oMv2G?jA!gpKkVplCp%?ijH!)ag$?vrUY_q{iOJa+| zG_ylA-wSBK&|eoSS>fst33UupZsm>!-I|4N4AasE(Nk{7(vsI?oy~yaBwnaFp(%S1 znzC_cz4ciP?=?3=B_o~o^bpUh3vJ|vt&9C114E7fC)8R>ag>2vIAA7bv-B@2RCRO_70bgLD%IqXY)!{SQ(zq<^@_` z>+*E`6=$FA2yT`_D7dfgACunNNB18(!>aCADQI;+$?0CVX=N&lxV!r%8_+_7?Xx)Z3K=t6!#G!)SoBhZTdYwub$JW~8>d%vnJs1cs?}CP$SSGyYlIhcWPGI5^+4(b`{k zxWvpCIi-T6*gRuZ*1h}n=ZG5>n+G*(aI`pShH&UxxN=A&W@h}{`4Tq27!^1a)u6~c zC*l>Q^_?f86B)-J)qL9#aHbfs*h|ZWfR0~8< z?BUK7)7X=2g|$!WAWBWFRYW@o7uMb_MR@5Cs-PBIH%MdLY33>!&O4~GKU^YAF=fWt zWT>da6lgOrx56ecs5@D~0%d?qOm!iBw$(ogoRD~bRbpY)Y2H*Q#k)Gl^4qDt$*Neu zeD=b8e2oZT8;{ZcHfjY0A80|2-y+*ruM6;JJN%zJe5_Vn-b0#a<&^=RtnYBBXfRu1 zM|T!&5KZQKF0%ivH*B5IYXXps{zpg!ou*A8w?=skZSOxO{_iu+!?F{Bhn<7lb-|RM z_4VkR9S)=)ZvG)m7IG8VjCn28kKpDR^Q$1EQD*(< zi5Zix6D+rVT%Lq2Gmcq-Uq!e>^&&G+w=8Qn!(2n--1U{N)NcOor+r)hNWhLQ8=P%f zyZKa_66~2D=^R>*kE3O6=22$`*RnQ~alVFH+llj6mjNF}-ebr%|5bg;OjuNUr`E+y z-%eAVTk%h|EjeofJ3cXX=n~7A8(clwfsC2&GEhUCS*48^Z5S%|9jBti*^=4D%$I^p zecU}`Vu8|l!%`v=)jmp@r_#2cHH$4=9l=!ewle8zHkNs{=xBCYeZ7{1`Ic`pk{d&9usu=em z;)nL%)mA;-*V)GCU;(xq81`2TMo0~Vb*lWq(T+(qV~>|jJVwVQ*=*SE%kD(@+2C9L70S#vGjC7~(AOf;v(eC#{} z`y1If|4WU`g7dn6DELZqMmvMTWwx8VFf-_QyIJR$71o{!gG;5`&3kIZNm{EQ-rx`u zBQ4S|O;Lz$@wL}^c@)BFom!h*AM{&YAM+_R$ zrv8@dfRlio--!Cn@mEX5^-+Ce6t>{;#;vZHe=iDgN7sB|&Cor_neaZ6b!jBv>4n0( zZqrVM!;>$z<8=nBo{(NxU-#I5al=5L!^i1-+y}cgFOByDK#v{%Q_}dcz=)aiLcv;d zzNf-Ns)p!RhPH3uHFAvwb>h+AC12#%=MTgBx5txb)^QUEP1-=&uCl~+V}K`mD>kQK zFOIj4>}v~#n@7dY5|MV8`xI~yY1?{j0NxtLaYn}12~I{Ak=jhtQ-UTqJ2J)i^(Pm%Ibb8M#KrDC&L^D%wC5-c0*wzFGNU(cvfP{1W8a~5lpkTaUK^Et~_ zJlrkqL}u@(ew=bn?W5s97ltY20gkSp-f@}jToS5fZD>2m%~}GV?A?REygW=JD@03k zo}q0Z-_9^HOyHAg-! z3Jb=CWM^Dv27`c;jlw6m(a+Ad-&ZO(#g+Bro(@Mmdg+hJ*N)=XDB$|cy-J-kiWfR} zc6}yeuF{Sm#)UO9=E5L@d(;{84I4b<85fL*Xuba;d-ZJrv&QHuxKEc^J4Z}}M(y1Y zU28YzYw+!?@K|$UK!!J_`0eD>Es~RS&&iMBzO;GgQPCF=C_`7pAak<1oYUaS&gJkh zys|^$50|#Ns{By>5UtW18uvMm4K2lAayWJmZoJ}%byt1KFxWml>~bab^ervfp(QzP zswI~>-$G}hck5rjG(>#A5X13M?rzZWoNq zTpBYsXb)?wlLEg6l~v4j)6>^fnH)!S!s<7Ngc;^qg5V%^J(V>EhUL3m+;77}-)`TE z2F2?{v4bVA6K$2(iM9r>6Kyl^s46ji_4$oXyvVd}hcpN4sH3xf$$KJqJ&M5(x4S24 zRP}BglDbE7I)eyD(uVvZd(&m8|2K#qGv9W-qpMcZY zV~C(YtGe%Dm85PmsHL)=P5fytvbc3I7U-?D_|OIcc>+ra>IKwH9>vN_f71bHCIaLU zje-WZ`6GM2^0xt1rUmG2*3m^1<{owA{=K|ook&bhcpK3sw%WOSO~^pskPRjTccPgW z)a?CR3L!1GcOI&mlO7oEoj2+E#I8xPEm^Nm% zT`bMEv3;GiTT7nP5(*p~ZPAjmoWQvQLwkt$Rw1UU{KHpc7;Jt}JcC0xLZ#kD z>S*3w*=Al4;?lpPsXFG1L-*roT6~@s=Qx^{+^(J+vi=Co>FsE_C-UZLfDasPxGEuM zGFR$wtfMu5UrZ3H>gvg1M=K4rd#aZ7<7j_$h7YvKd5AwdM7*C6XC3Xb2L^DovvLXw zYyYPoN85g($Vht!j`lrPMo0VjVRFuKw0~HhU*Tv6IAwi>qg|rarbCXl;d@qpxsGumB~6j)Sed~!1Too}5~_Ke1Y$dwEY zO0p4KX;wSO7Md9$nmA^O-59*34?9?Y9D-@o6g7ccwiq|=DQwwiB$*XHxh6FhYN9?PoD z8413}+FyiPFpC(>FAf;BUL*E7y!;eL0N|aK_!jZ53*p)EN%7KG0qF=ux;}*T{SdPu z=~IDpm?GU0Lb^VLv|D-~2!hu|40`F#s9BW<_MA*-l4keQqMe1SkAXpPqcU_19AjI% zNjleUPYnZxwna9@q4RcM$0#-I{^yDL*qkJUaGua}Zjc?eoylg)83t?VH*GfGOzzhC zWi9~q3K3fE-=vYbF+fWWb3PdO>x*h=x8B7gG+VLgu*gH=TvUlT*VC6>NK~oSQGhnkyHp+KO(zK=&+CjL%|V7nl_u@hE~+dg zv5P9T-%$mKYLZ(-L7~|4$DlgAMit7F*kW|ni-rzwsGEu00m92#M{L7OvFcPqHkp}U zOth{e{d=7_m2R9q8I)whix(Y|88 zD zL)k}Vv%^Z;H=C`UTG{U$uT52T@N*5A#Int%R`n|09$v;MT|_#5Zr9e5^P*OHXtCye zs45S2?YQh^W!RxzC$(QI!HgE2@K|WUu6j9u57h~ty6yTe1Gg>hwbS;#>ps}9gGS7C zO}2~7Mtn?e;a@L-VHlfN7g|(tj+*N%Y$VKYVRZ5k5cJygN=k*%oa(QR;^Vy5Zc|=j1Ms>~r3&w6?%6S)==$ zI*5L7m*`oR%6u-^9UkAb738wpqJL(C$|<+tY^ojow!od>p(@vfF#d6tV5ISt5jQyZ zggCZ`P+w3~r%2xF$q%uW(G@}YyV>d+Ept3Cs9V@^48ZswB80FO2v(7$#o??k{rg zI25?JyBO?m5*=H#JStyU`|6Ouef}Ue!K|PkWbEh0%uf`-%@qD;we2hIXq2o!+RYVN zH`19xyZNyS1)Kr+azc1pfE2{ecJq5Xud2(9n}u}`cvk3kGt@<|)%3e9{40+Sn7P2= z;{yh%bdXIfGpE@OUe_e}{L4L0JU+mm?(qSBZVQhO2u^d(;{%tgdVkh$S16_W`3<3h`BK0&ZjPT%(d^XagHa>zCDdMxz|ntw5CkvHRPP!W z?I^sRU#c4j6~VHjXA^^W%sj6&3`<|^gc1jAkSWt}tef9rB8f{HEqXS^z)t`A>q2e2 z^K?;{bVID{2(1Rw~LsM#9(d@cw{CjTiF3ZgPvvPU6#( zTdsnxz4(O)96LTW zhXlJ$>es0@BFy)*>bp!OOOJ6>4`$28X_+l4eJERUsB4c~P^fbcv)SBWcQ+xhUs{9% znQoGBv^W`jHMDo9#1*c?1oOC|nj@2Ye#0c$iKCH--4QdPR$UdJZG<~EKg?bCZu5gX zY_4wc=cN%c^SRm4yeH6NrcufZN@JR*$!^%sx?Sjyix(e6(@#q!1?GQ}mK_fKyGn50 z|7$84IY1>F>UviKnKAx%n^#;tcrYHV>oy7P0|IrK1q$J5ciF^Db}kQIf+M=vrsa5J z^({kEx5;3toFnE8#~F`~19y$NQd^4Ng-M;{q+EYXl=6^1DA$uaa3=JHd&EpqPE89XW+M)7v3VENko$Z zO^P%b9`ipGi$=_q;@hK>-Mc3uHPxS8ftdj6+eqf=Z{y>Om#^5Z5xXYdJRGsZe2SIe zS%giuS;K8?h;FnJ&~yAj>#$xpQgy&je&VsiL3n{gDJExlahDoao75#$@O49M8^We# zgM)Z_w*3)RN&{Z@LsX2J1zrL#Ti99*AaxLkFttI9N79bJGQ+{^GER4ntG3>0-d*XO z43*%%y?lfa_wCzcd@yeFxQ#DonB|E1jt)kIp8yF00c!9XO8Jhm)1`5E2TL8NPkgcD z_Ub^Y+PqwJyy9w@!=Dl0^OX_Wis{7XR~_+Uw5~~~MceoyCTUa}H!sCi*C`o<(WjgB zRlGQ|!uKGx)#vf;40eWxcg}L>soR_@&47%HYi!$h&=R(^)k!qPm9|J-JIo)PH)kZH z#cXjII6~Ip71ljOJy*BmgPyJh-w`c#j*Dil5AtpmrD0mqDUZnRFh{6bVfX;&3Z)wy z-65ND`4##89`GH0bhA6~`~dqH&fw2UX`ri}QVvaidqqE*yh|buN{6^or^#B!*J-lKWprYzm)e4% z#RvGM&ycFVP(1A;ig2QA4)@hlOJ7uIfm393r>&u0$+yVd>pWY#MS)p%t8Gv>UI21f z0=F~aZUyEkVTvaG@8?pEY5oPBc1eE)>e^N6|2T6t>%Rhcwsi#Vd15-^(q;58qhwUTRH|}`=t=o3>%I% z@PH}aQf>I&mGSv9v?6r+=Sf?Pxk7PplodfMb%gB`L;MSDTVGJkQ6+g&n5&YQMf1hP zs*<;y8laL_+;6Dl*I||Ho+ET&?GO5>{~D{IvHJ>!YKW0hSm6Ar^R@c&c00D?or0yw=E4_E{)_GT zqqf$Ux7iy|)*WTs!AL7xW7w(w&dt(93?Mt{=r`*3C@^SXtzbqt4Pjn{cjfPai4H6& z!?nB%5br8L?Eb{m4OC(WhwaoC;xiHPaBvX(qSC@=@&-qT$IQjrN4dBz ztfhMeqmVH_6thFpS8oip!~`vQ%eC~7a7%3YX!EQq{_;~%U(Bx!wac&?Ebguow3EWmgB&YnTcz^!6i?OYRZ_e@l zCWK-j{*$_u)P#5KDs*WlZ3An@Bo(gHKDM_NY-6nS55+_t(>l!&XmY4_Q*{C~9q5qXUnaf?-s-ei|s zyd{rtI#6JSD(euZJA@MoTRE5hmDYsUcJsZGxL;)H-uzN{hUlg!o&Ts{3^#wZkw=dW zZkddVJiWc#YH;jssJ!1*~IVuBID6A8yO%<6D@A`3IgvYq&YwGFs1f?|@Ur`lf! z%^#Ys+<1V7hc1vE@hkS63ko&2Sc&DKBU%a{xtriZYk7_gZYxPATYrKf~VcJk>eROR@ zlxh-!b(UbCK20IjYV+>=;q-tJ}fc1!kWopXfhk^MGqy|!a!fP=22eq5*#e9p+x z?q06zHYKZ@tSgi}rVY5Q4`WZ|=}9z^<pl#|3Ioi+TX+^1D!f5e;TqFyDQo&re#t0+xZec~vv-v>5565LCs|~o-+?WI z-zpkI@4@0>aJ;wGUEGa4xMyciyl$-?1vY=Q(Gf;unD@OOYwQ2}pI)s`-^!Ub{9&-A z{IheCHqfC)&M-ccx*~(|y?PAu8MC{pRu16+0V`kZl4MN#b;4Xi&qM~YDauPuw4{zh zjtrui`aJDjXqDF>@!j1VUfH=GdBHrYofzW0cj4xwC=c!u+3seVc?|n>oXc!W!g;q!yzP zt|PZS{)`{I&4W?Z9}kUlF=5_Q!IRy*k#x4WO2q9O;|b@Zk4F=^#^Iq1FwZ@dp@V;? z8KO*5@J`GpUEuCCvz%6B+$*eoT@(hJwAzO8Ed!giZQPEK^*4_yFu!t{=!P2@T9uBqj;yc^%jb8u)<#})p&-e);ensSWOTce`c&vL_QmYxR zM&awiP;aZrS6HA%}h`1G_yK(Conv;zr+%irvyV>= zb>e)LPtDV|_3^2L)xKZpQ_GhO>{A7fZ^);%FAe)?U!NKo@XPh7W;IISQyUbvKJ|0; z-mp*oHH3ionJ7YkK80B^cQ|GGGuZbKf6Ts%t&nO&_|kOrRdjbRb%4Ytbe;l#l0=1$ znAxh#MV1b8sSCPrv4}rSf_28MTVz@4q&CcQD;Vp_!k;17t!AnUfL^MzGX9nEsMY*Z zj8dXuEfA|lVv+Q=`vR?pD=7nlc@9F@hjSSe1M2ZCycKntQQ%%5-7eu_N5yV@Qu-Ha z5eXyP`4n%tW|&53Sl_0H*~?XsJea*)1HjxRZIIc^zA7^|_s|ebR$k}h+)J(%jR;>1 zwp-0#)MDnhBIWZU!}E}UWuG`?S+o32nuvk(0Trb_+AM6g_9U9kxr&PEoeqV_dfVBv ztzj0|X4osmGfBtV+`&>42EKMK21lEyy1k5VZG-b9ghI2;X0j59owu5Qswb-&;TjnJ zs8BcjB|F`>WrRHfCU`{5sX7U=eTv_Sk?c>j&TY{hvOIcQ%;|=P4l`bD>Vn%y>uS#_ zmF4l1Tpo7|4|re5wn=JW5QS*L+|qf9bmR!r2yaft{bD% zlAXhIKhAS0C@YH0Lam#3SGetpeKNh3a%#gY+;4$Ec%QOWz+mhdY%9e|jS~a>vU{-j zRbcaQI2Ajh&Vi*)vM4YUoDNZrEs6{VMV`$XWrm@7^)CX%tEn4@dkur;<0Q=puf+4_ zBS6VYm!GkHLqy4#FBVu^=;)g<71~#^k0$ajKiOrE5M?}a>5Z&batyunQ(u#Q0N-&zHhH8Fdf0rL1r+^ zi~Wft?TKLSeV#^Mia*-_feh&dW<|Nvy?7PxhQg15@Tf(&+9BXGW%=Q60X!=`79R%C zZvj98e?14-kF__Y>Rq{h3xMT6VfpX1JiQ2Qsu`=_0$}0KS-8O#PLV?W761!3v+!P9 z2or%)zXia;7g%_`Ez~zqLA5*4`D3O`yM}%Mfctzw1786Zs7*B%dE(<}V8r(LLi;9j zc1Y;Lp-xrQG`7WU$?q+bv09Sr=n@L8{_IvOLt!`LTKZT>s5g!I!v#S6vH=jkYyj+M zV-+zBZ!xj{^NH@>SQkG_V@$3j_5*6W+D-25$B+I$*-fnL`#b0Xap$S}c|N(-mzO@+ z_6}@scdDYGZ~KitJb{nCjsSL*BKdzIpJS8{48?&C16a}ZdFdm8+AxEC;LsKf#8~J{ zpTn)T2Z_XQMB^S>`c2E|?_~5h=UEz8T_yiw*)}a3ppr=MN^qp6ZzZ3S(XGnJ*4x9Z zYx{9V8+p+7;9Em^=`--r476)p{&)GIp#+{^fm;XP4H~*$JIGaYq=Q&d(|AiiK4O#J zWE~mNLIP>SMbHn%pMpKc=hvT;pY^|>;IkHd%BcUMJ;q1s&xs5`lUsy_+IXK8Ak?H0 zkjH&EDavDGduql+G!T7It@JutX`{bmma7;>7}03Ner?Izp-#c|4a#f{h!##AFF+df z8XSPk-T^`X&o@`A_WJaHvI+V>7=;PhUG+gBi9hBPb=<6eAe%LKA&g{hx+VzXcx+AX z>3}}u`ET^`d`o^L$;T;qm^~s~#2;-P;7V<~jg8sa+&E#XQ zHg72_+Nu;USKpa_EvsN@-1!ii+T|>#Osa*mV5m3fXP0^GlPk&7`7moaOC0(mk()`mn#Vedn? zurp?~;#j*hL~DEXkE6e|&aVdn@G&B|_D;js^1&3+CnUqD$nZSanuk_oJrA7+o@S?* zI=Mw?E~to@Yp%%QjtK&%8(i{+X1p5hbNJ+?OM!=#Q)tP#$G?Ra^EqSVofiD&2RbJ^ zbxMyvOQG;!CQGLHZgMy?n15fXH6*@)6koNf$0E1DPPyGoXDo|2ph8|*5{io5}vAEHbeX<{J;u^yjLhvRe-dYE#r1XUOM3Wh2AAaPtkH})8hdInm&_iLovC7 zV^TRD>NpnG4bc&jM$#`bixB9!eWbZVY5#tyYv};eESBm*llLL+dvYNO9uBxH7OSA) z-=rb5;kK%q0;Eu5_tGu$3K*K`Xlu67znW$5^$`j|Z>y*)K4mACM^7&=JC-94l!eXSiI~h*t z&1*>NU=<794IFz$_nc^a$1bk#0=2qJ;GJV)udMfdBry&C&MgDp6?PayQhFYd%9B1z zZ$mUd5WvF7Rn&vcW(ne`=nhMrZPoj(RL)?6QmlZ{Hs2i9;t0Q$z9h@DGQVe8zInpY z#q-i*P$=3&SC$TwJ{A2VKA{d=Z>j&5%H|*5NdP6P7oV-{3>i4 zbS=@OY_c5UWMQx2+MF*}u+EYGLv~Rjtg%}u3+LX^=VUrZuQ*nFxoALl3%N5fcba6> zPsq0si39&EUAgEm3@mhB{}K3%oMwGfS-=?X1%k)#?FKFMx~}@VTcC{8aQKHr`Yuyw zDXNPix8mLlizVcIg1>@-^B%5q)F!KIJ>H=Suzm-uCPAw;b;_weT9d4<;XL_1F@Ftj zTO;Va+kgUl<67m-;QjZ#4Sirn;ZIQ!^x0FUG_jIXTPTVg3phq8OR;K=aL{e;f3?mvXnZxxTK2XdLa0 z*+cV^TbRcI;x5<}Z>u6GcODz<=i1&ago*`VY`{x%|}b`V>Gk(v`%?ZMSVYKSt5eq2w zeCmg9VJtAqKXZ*oY}4Jp5*(MHL)iJplqnX2=ig=WhH_c*vY8jA7N;2s1{xa&_Yp-t*+s0{HIdq8w)Y`nGE<`>&)UAuKL z^+2}W(!b$wE4AJD3ypNK!R`UC3&EI8vP0)B=;AsAvC(2dJZjEG2USx3X;>vv%IUl` zIg|bgo6I4*t09J$M0c|Z7*NoJu2fu_fC(_?1y*|LwOD98_AlYe+i1Lx29xRDj-c_D zRioUYVz&}8z&d9Brn+~lr+vi%yUi`y%TkY`rSkIW+V4r5e5xn@OelZabO#aoEGiuOF{_bGX|CXGYdc%8d#7i>fM&FoKxNhLpWHIc9dRuWN8# z{UA3YWxq+yP*h+}w(-Eeb%fcnKS37}YI>rLk_(>7Uj>F@^$J|@{4 zadW)L3T&S+awJdWlKg?1qpCL|ysyCnqok)URZ27;GucE|yFb22gs_^S zcFosm7l+PrwL3S5N2zMpvH5!KW~g0gfj)|ro6|FNhyNikVqhy{AP(5m-^GHwLt}d_ zjyXm2<-eGoV5KobRVQ;5qNU$)&WY#mB?5{66_`bWDDNFAGGz+5w+S?P6~vw?i9w9{}@2j@^-rv`QDy*Bjyh`E%557#zbX(+H0EYjbzV(;#h7~E*S z6y0|8wrC5q?k>N=v%TquLVG;17BN z_!AtyMr!tV{{R*om0Q5MOas1D&^$P1zICD0@hI!(AyGJOhj~q`kUy9>IBxQVk_*lw zM0~|NVq28Y4#IER#zk9j0{lpG@+9s^wd2t^9yh>5xvgP8BJ-VK?R+O#8*hmtd+-p; zBls=K#^9o_TF20GGBHe*`ZtYtIGSN|XSrO68ZqBeQKc=@Tr&}^!>GPhXlmJOo+TST10jFdTt5 zCJWfA!NshCuskoo;?mqx2yjfCLf~?}wc#Q&2uQ7XoN5rBXK~1Q*yqlD2EDYwYs@cN zH7GsPoIWr&9GoCGEQ(qiW|={FD@bcY!VG#vn&lYA%yLx|Iqwh7P2@b-d;n89DWRx- z4;8MSVF5BfYYLEhk`xoj1l>1|7TdFhd= zn3}OiConFnf=jsO3ajl-58o!2!kV#r!n)Yl#M`sQr&HswQgDPYpus`1hUoUj^6o3I zmI%m>j?f|QTIrlX{h||o@dFhKlNdWg%Wi&+i*~{X{l+pRcucNts(PjODIMy#z!QvNTwb3sy6QwKgvGhse z3f35Kg{%`~-zu~=Y@T$hh>%WR0E`TtTkwyO(1`W9#!QHx^aktQ%iG~T z|4)109v|0H-#e0a<&7l2;t(7X!m%6~2kh0ucCZ~;M3!V*L|!?PoY+apX0^MLHeT&+ z_F>Beasx>qPza%=Bp1>ErA@-436uhcLU^{#Ep2Xj-I`Ylw-n5yX@HbZTH54(zrUF| zFRf(d0r!u4_oLA{-!n76nfd*G^PA_H16@KxZaSf~hP1UG6=C{w{{2B?(`4S2i;TXU zM}Pbt*tb*Pg~~6Kd8~s<=3%UG-Bm@qjqB#BE>x!})Fq}+$$EvtOb4PkHLSxT*Dn=0 z)GcX;u6n+b{usSBuI$*t>b~{mjxSbLzVWYaf9kA1 zyIe(}?PM*kfa0ZoxG zl}*4^ul?e;lGuyebm|%~R61fhFZ09wnGSa{6mIOjrB7jq|HM;&!E3ecrk_Th`upE) z;*Q714_&1@Vq>RFS_RNJwF2yrl=!gj50k>Gfg6Jt_>EUn)mmkz(@|+r-SO`DmQc9y zZ24%mym?^n@J?rMIhPsFRkKciW;R!lCzX;Jps#PL#gr&G<& zRXb;@vw3vk>->6WvZ+j8Z#7rVXZt!Ty`B25w^N?CsNTt9=6GN4Ot<4W;;-*|JLNh2 zOMShS*;GE?hx?gw-{E4-NtLt6T<>JrJgc9w&P;F0nJH(dcC~j@Iw~(u&t`VbrV6R) zY$jK3@7pi88w!(^(#3d?O;?NMTqOm+i1ma(joveVr zI_kb`zGTzdJ2pO%OpGQ+h7*^nv7y1?v7v#9WZ#<0dszt(JCn zb{;!+EItj9GRb(cJl)yeXC*A@QYCsjEprvZR;n|(N>z1KcJi-l`yu?>hJX0uqd>w2 zSpDkh>T*UeZCOA!l+6dF9}VpSdlOTBMss${e%056UjZpBSRq% za4dPCe_|gVUv_W^%w$~tZ2q<(f5Xt_av_y>w9-36<#Ms?X1VIAb19$76R1l zL~=Yim{6r`xl$~sOd%9=Fo8JZ6XTk=i|S>K;ShWO=)_QR-ze@gg^HRfR;q>6Y*r17 zCMKBL#Nh)&MylRrwwABvN~v*iq2WLZk;xt%I~lJAW0`(tmQKjelqLii;!u?+3e)32Oj1M z>0+4{Gk+X3%d@F!HJi~iZC!V(_F@@yjh1VlUG55lHb5_G<=n20%7$ugHe0EtW=p#| zGVOhd>@jUehbR~tG}9oUS&&C)t9HV`&9ncWD0Bi^u!SP1E|}O5#2HG>(WRPCKd2KM zmO_3|)OlV4X!~q4v>*%Tr|)X>f~Aq>U8lCcn8}iNA={!YnwSk=HK><~-dv#sg`x4> z)jpHUWU_^JhZS*GJL_A!b2OE&0d!Q_>lUWBB6ow7?mye1?W|3le4+1OJhuG zq*Ea`mRYfqb|s~d3iT_QhFQ%PJWlEQ3;$dO zb%w0k>@W^Wn?p-P8dA?pJkQu?3Y)d*D(BVF;%r4tU6*1j;4|E*!tu?u3heA6zon)x zIaF3zJ%U4HW20j`oq<$=)R9r=tpDYDT;*?vTeF14;SV zd2(j6)tO>uSNj2U&f6W`c{M{;SDWj%pNrKmsK3XY1=`=m;=2{bqaqf}&rY!@0U?DN z?QzqF>pp=r)c!6*Ia|s4TX;bxY!BLFF~M%D?oV0Y_g1BCnJktu?%37d4ZE1l=Swg} zsA0R>do-?;Qfa|m?M|h7Jdeg+$Jm@kZA_Ian8>hq?HJyW7;q63*LTaW9b@cFbp|PP zb#=5mIS6aOwNVqyLpu)sp8xBu!aP+o0UP0w>Ocu6`#eHUq8Nw5aKdDPDBEJ87c=qSUH_>zls=e=k zjGCPd`Rc`)!iMSU#d6!J?|pQ_@lCg@y>BqFS!yvU)XI5}gaJMpHZS$A^Xa1^4kpGW zJ9Y@}5%)h?QVL=E>?*eRT|T;Br@&65N8KVH<#2qrf6>=pIPM%o?=ld$Q;P}p5=si` z*HP|1%wc%H#hPYo@{=6$1_nyTv~x)28X;-5Hx9~B37UX0OQ-_q5d>!u9oMT*4|BZy zgzr2BX8j2cKRC5%^_4lYy|(rir3Vb#U`~wQDOCR;EywGYD2Kk1Ww%~Sa>%H3PPMH; z5;O-o%hbEgn|*yOQzog$0nX8b21q&)81dE-O1M^fTv$v#wm&z2oE#KNe=`mC zEK?B~wSY6GSRt7S7tjOf>u0l_&Fo}>9mmTb8c=_8k)Fw>k4zTltXOPo@5*5`0gKN- z;H6=tOz-OZ7R+rr7^fAoHic(GzgAc*1&rERpuub*hw|ujSt^@i@Oql`O%G+5B`rHX>`x>{C!F#A%ZHqSef^2OL*tyeFZDTgf@ua5P?Ong!I>>)a#LUp z2Hk};CX&!-!7HCakLhSG3ms@72kmcR`YjB{6u2aiw&PP6Ep)%jFjG^Gbp6qrlCGKb zKsivt$_BgPx@#XQjZM|NUeQ06z-V!&GkRcXtbby7G-1j&=o}tBIOgE#{^9X)JRe^d z$Wf)5!zg(sb<{4WpkB!olg0d2_*b zLVqw<0im2unSE9>6|7tHT8Wc{GU0Qv4CwV^uyJYeC8pts$9vvc{sgk=CgD!rvp?ip zi}Glg{<%8=N?CBZ+X$P}@(a2Lcq!@!&dBoy9r31SMW}U1CxBp&Nr` zoTbQ5mg@8@3QI!Mw=@yXlV4p*3ybg>%TJdLIrSuG9{u(u7gXs0vhrDc{sWy#v6O=% zuz=|dP@50t@!v;cVXk|0&_Blfh<`?;-OiSvJ*w6>x?Xhb8R!X&z55oOpF@M{i_6=v z{QbRAJ=0-F0GM3cWas&~+JSk!p3`P8Fu$dzkM#hVb>325XzfJu=j$E&&WWMb+^`>uZb4*IP1Nf}~5>MnlGgQVc?CU+T8s$I57C7B&CY@Mx>e@K4YDqyC5H z=j%~gM9sqbvE=q!%2ucO*3W9oN8cf5| zuPc8{s$i$bq6%QliI$p#e|ieAfc!(07FK{~EPq`#3~#;m-#q&5%YJLuR?I9{u?&vQ zADjfH3Da`2@_8omXMf$suPa||nwBnK3ICkPH$>?-AYWa!fPBrP-@bf8(E*<1AbJW}s9^66d@v`j0u3I6x*JQ) zs5{Gzr9t^DKE84VW+zIp&stB082RkOFdRE4nU!GeoyUJ)$bc@kV_k%Dz&<&Dx4I*x zXQ(^OuH=qMgAbeQk)0j;gDMk1Vfl@uFpq1ec=fh(Z)0&FrUv2o!S&qkz-sO`?C;Wx z8-0W5H$X>ap|o!tb0$t|3fsr*BQEA*&9|_tr*B{;Rls&{XA*k^8J_DW=(QZ$Y0@_Y z#UlFGUCX)YnJU(@EJ?k2J;MtM5fEOb4>Qyt)=W`C(Witw#3-nh$TDB zeQW9Xa*4?GeZmVWvMPkE$~usL8ZFFUXfu82vL7d6=0DE1*Ac zo%?zE>8Et%@Buv;>avsUny0CA8 z68}|M`3)&H7$BIZ8kUE>ordZ{j4@^98iY;%G*cA|4+Rf$d$K2s_C8uRXyj?f_U^vs zz`~_}oERRgn&CgPy%9@p!u^W8PysWTMl~_3BNYsRJ+tbhuxFT*xP&vED-_sA6Kky3 z72^6Lbg-ARh=t5JmS~s4!LWWxiJVdj?=$EPhf}#iHnVO)DH#0}4wmY49p~wv7jki> z^XtvEY{Hz)bIyz7FL`lL$;0`_%3pwP_>~jBLc%7|ZL)No$MT@`puuBK*xG*0I@1zW zF{@k7PS^6OvdCebJ1)isHC=_ofSKhC6uNIH;1lkaxrLzq`qV5qr8UmgtF#zU)XKUt zK>R(-^kQ=+VIA}n@+a=sTW|h~3v~<4Zg74Mdu1>Qf&NrV&(PRu326g%ZSQi*#bcFS zJ(%;Ew>G91#Zcu9fjULB{UdVI_CxBj+IR*US8#bz{vIsheG1tI1)J zLQ_&9_Ug^d9c-zXzE8Ld^H;x&QIE^QU)`$cws)rQ(rmVbS+wd5I6u>ufThqtx2&N8 z)ZLBX&y-!!*TQROC(B*!MqA)6<|7T=+S`^|C+8>SFQ0Vf+zHfq+t%D%qI}rC;9yJ) z@h-$+bow+`FY3Z(+PS>E47Y1rH|KYyapIoh{@wH5N^&2&$<4d5s@Io>PDu;(4Db5wZfxhuI?gatxuo?(x|*)<9>^?aY}j z)CN{P>Ajg=w@cP#kWJre?P-#8ANfb?PBNMWb234D*#?*^%9I5$tG3zTA!kQ zbt>FBMHRIhUT{l-jPH9Cg1R&9_YdoUUjH%sW4YoJTnlnX1a6Oi`y%bxfXp{Kvh#uq zG{{@aLI%WZfZFvyly8DbBl&JMOXcs_ z>&IuG(2Gnp@I_vl;+c%rr>|#ny%fe|HPcN4mV=WB{5@^^w3VBuWxDTa^qKKan!N0b z-Rpc)jh#DxrSL1UXSc{C-LW$o=C>`uMR7l|Kn>FtQ^&{4b!<#M+xINW?+$+!>THII<){|$3TXhO65)b}++VV&HG*b@l)A#13thJ?z$cW1A z?AS(OOQ8OH>(XMoL^*n7n(SHfjTs(%!ZR^@`5Gx{%ch`}x zIpQ+D(-GvI2POZFzwfi1;KB-2mIISr~4i`|`bcvveX zYk^lCf`-8$4i6c6KiP=SpX?sR00KwgODtW`OCT@5d{>$hTe507Gx(=6uu z_3(0$_}GCVJ0eQ8NxaYK9Lbs&YYn~A#>XDP+>~smtYG2}N5xb&|0ORe!Y_0NWXzb*PW$KoiMq8SbQ_+01TPajjUtci;!aT@+x z{ebnjmTzIPmTM(*HKZ=v-G`^4FGC{=mes^5N+N*_pC&$D_Y?i~>jiYOf~8$e<}~pa zF5f`EU)chAatnu>)6lp1!#OTBtON@Cums}EZVS#fp_xh-XJ?Cr1o-PGzf}4G`GgY) z5DbAO=HF)@K%J|ifg*&6`rs1jd&>fRHHfQ3OH5;l^s@!N&*?l(;wZ;y=*#S*-$3~* zAQ#9|>`CJ6hD>f6_IbV)Mu+WBa8~V#YpHhX~t7M5=)DuBXNO=(ob0Qg)oy(>bUj;`w$nXRTfdCbk`N;Zv!-0E?>SSkc7YA4!DY$7nroc@E;T2!Zd z*3!sOVlPgsLjS=%uL-9{jU7&oPmJMpBNYG})P@f9tyD)xN6#T&-Q?}7agy9?@V&R! z!My?Q&2Vpny93S!#nF^gze?x*pdy zJiqZ>kr+eGf%8@ z5cw=z@pS@)Z{MhE?uf*AzYo_lamA;A)EYSE8D};YpLjw`FcR$>Na1X;h0{1A~lW;5k2=U?KaD8wIxU1m`a5uo+26s2y z{csP$Jq-5<+@o+$!mW58;={$^`rs09SHl(HZh*TD?rymI;U0v0814}`(TlwU13R6K zdlLsQbhgBM;yn&lYp`Lmr^neihH=V1>_{5P6>4+Zck{Lj(eC{JDE|+0OsVsrIQmph zT1Xt_30=BC?)1M+xHKx~45hR`Z7FRbZ7XeT+aE__>vd51&$x~1t8Vyqgs08@1BCaV z{<%)V-HiWtL3eM4OAe1FD^+x#l6a*s0}mtuXEH}yDw$(~Sg^x8Vwr5I(wW<`{i061 zMB7=x(t0&Mt~zU#a%ZKS?wrJllbOz*E!|sp?AR>9b{`xb8SI?S=O)vedoTgevsvoL zmhLT`=}JwZ-Z=f^PEWjhOMHj4=-XApjdvnzjbi>I4Lr?<>C<&0NAE=DRz=YGH1@(L z*7%kt9_HWp7NSOQB{G7WakwaN8dUQnnw7}1Wjtdr5{=!0hmoel8E@p%$p*rfF_3E- zndI#;JZ{?mX589{k-KnDC-j&_%eq$ttab+njjjw4zu+V*<*Mw&M)zZucga%w@t@?Rn4#^w8&;_@HS ze|ZYeqs!lo`{w0Tuw~0<@ISWv(+G2hYI~Ou*}nWHvU~Y?XuccOij|1di$u<9-rYKf zN6m-$q-htzG+%o!Vz5}h27%^RuEDdW|3uj4BcBtGNb9?ZvJBkx1}2;Trg+4f-b7Nf zKZ1AT`nIO$5fw%eta1G+wKDQNB(Z87{~E~X)x2AsLDaR_iOjA0nt`3$G_HV zK|Jz}TMz{_4kOYEMtTf4z0EIg`Y&9YYgb7ks_7T-X+D|~6lr=8QJUwpRAWt7GCQxz zi(gyQmznYFHCol0px?eS{FqB_dJo+7a^pNU}zY-6pX^QA(otq1q9%KAlG}_qIMiQ^rXj4-SF`D0? zQCHJjiQc5qR?Xr!YZh+@L#{>46@<%?y$hNzfiffb?=M68RIE=DydeT>$iIT_n#W1} zeJEB#Y-NPfTp3}yDOKCC{K?jp8jttiai6E~FP*)(^mF$uUSy0z)oh!gF39I223Ygcp&gE3C*1_`vSMFMp)P|IJ! zFS?b)RO^qJQaj7gx>XW=J03URPV&oI?*QS(3vOY!QF?ZKgr2WN;K;Jp>v7+>@r!)& zCkWBd+&YMq8!r@EALi{#zDLjVn3HJh4ZOUR)LUOh>YK>d)~}Q7=396>0I$X#TD{h9 zFx@TZQ-Ka4T5MVC9){Z?p0|_GPI|U(;O$LvTjcG{Lg*h!=oYzU>(=;s=DPJdvgZvF z_5t4BDgo|e*f+}UCWd{pD_Y6k4rSZSHfP& z+k52p_eu9&VaZz=?E{jt_weZlC1?B=VB`Jr^itkFAW!)@z{Wopy7y8@A7kUvdV*06-mPXJ zgr!YreGSrS{>WYlOVw^2gI{zTD@N--^Y&#_LCQr%w@V4$g>prAh#KAnujtNO;P?EK zh}&?^JD5K8U@RL}HJ^$9O)Jh_(XnC;1lYKyp(17T0h*SprWL#$Ub7t&43P%-4X=ST*Qwz(oe0o;0RptP_ThFJZe#j3_Iw|WGtSmD zqKw$$5rn!JA5ce+4#eGbmv2Oz^FVY3bHfyLepaqjtrB|G^YHw|ZH%}&io7UwCcV)7 zY!Gyo_D2J?29$c+V9J?gXy8_z8&G+9TO%h;gf9V}fKNVrndl~uS7>PX^@B{V6MOPY(2|B0KX;gqo8B%P<)^NPQV=9CUraR5yCyZ)G zAJc^zVJ=-P991e;$W`NMWI>MHt;A>0Zds}GPJjUBsn-VJ}@?XU}AI(R4s+6A`f;iSDhNp zSDD7U19+vOs$4*=L1+wxK|fOwsyOYOXHVm?q|KvwagYDCEUpC{no_EmLUvyyF|Y|Z zS;*oPXPn}WbBqy6CqG#&9!nc4#i=O?i!T7YN^=CY5u~g-Bee?F_tJ%`4yIFaADR+R z=8xDAxV5DACa16$(ge{-3-8ORLIuapBUfZ%vPQY!YD8h!X62yc>C@eldg%^ftHmT& zxfmOfO%l0`Qb$q#Jcq{*o$CQcRB%2e}s=_l`L##BBv4V^YA;W_THf;q{T zZE)+4H&Kcgl%9tcW@+QiLBqIjI}8CdE}DdZ*uw8pZo+oB;KC{L+sWE!Zl zP&iRdX$2&L(ed%*NIyPskxc4}WAt~b5`f6Ou94TdrU=!^Ew{_2;LMq1M?N4z^MTMh z$;9a3Zh&;Ym_8yo@stCmPUPulC-!;pI}%bqD~N)Z2_zPZYBFod?jPC@x-cW=xzD)h z`fuamgHmp8MlZ#!EiRw$m3nLx8Q4%`C`G~qN?5@g!w zo0QSqi!Z|Y%jQ=C7*3uIV!1TDH!(Ukq^XbNsmo(6emtSM(IwF&HH&CotwHkDtbo<^ zE0E!M+6q<|-QSw za7M*5#|wz4uhlXRt}E2yX3;VLlJF~M^9-+VO8Kgavqq^ntBZ=`^|lJ*KY^~9di=&n>~UPt*L8o=*8o}%hw-6= zi@i1yi^0PIwm%N|`0Iva2afc(*2rNF2dCDbS31rwpwBJgxCVJ6BCR?@$7Pxf!~V<5 z;m}o-a9p#zeT81D#3T7JEPs39(A6n2U9L5L9gCRl@U-djIo$*t*C%<;HOeQ@oj!nj z=Gmr;Tg5IcvLkW0#<>rRo?PR!^mxTkROR7pIIf9agK!Q!>Cf`na5dbMK8CikZg3+Q zkD%_4;rJ`T*>HEFKX)g>9biJ{$8dDl!`W~gDx89VF8G8AWWo@=7S4ua7q{)(N`a*N zv+2IUgd<-rLAXm0?iaq7$sH5pt-f$u@yWZb7dA+KjJJEwFCa5r%8nm++m3MiY#>~1 zy6?t4dBSj9+r1It9>YE5!5_o1`1iqCdi)|==_L*F9FOH^={*2s!_6Vw+ydeFQEnUV zMufW&;VcajwD*7E3&*wan-R_-lgy9d=spL>e6k#W{OM@yk2f{Q`a7WfEWN)3V!HOn zaNRz7*6(2iu=fmmGTxx(Y$RNn7JuJ`^M^ZtHJJ|a(f_R9zl6fo5bkE*_7)rN-$UX4 zeMf`ZZasZ|%ka$iSao0Apk7_49BV@1KD?_z7Ls)CJU%-nT$l0q62g6oieY|Ci;jB^ z$YcAvVX#5Hlpf}1Z+Z1)NB!q38dMi5+&VnZz)>En;8=J4^fpa4DB2GDv-B+XUuiFi zF)EkGw2K<+lxhDo)+x}=X{@z@_Do}~?RJj@7Pa_T?34DV<<)yFG?r+x2Sa0)LWy0` zSPPc+Lt|PZy>zHCCN=P*J^NuT7>!VLj8Bi(7hciN>1YtT!5Sj>G#k1uP}$(Gq*VCUuSnaMz?>5W;?oNB{Fe z{x1yS^F#PWA?$?kxeO`gu}BO_Q&{7 zR~}({_k{9uB82}YgufHQr+`nc#|LAPDVFc&A%89wziwMJRy6)=U}AS&6palT+yVSL z;1Pqj13&*|(HJcQ>2Yl}v%?FY27W)V4bP1SjeXHr*@S;1a25EUz$nJQ3wY;nGJ@w`D!1uu({}A|0xUU1B0A~4!e*k<9!qYNgwq5-a_#yc7=o|V+ zK&bT5NQ~Drkv`YckDZLf-Y@=bYAx_dgzqxpHvpdk{=UI41CCx0jTO+eF#dkv>L-vs z@=yFbz)$$nD*(r^7w)s-4_*S_b$(R#3Nrj1z#n@-G)6uWe*kzb!rx}n`wZ}!UC|i( zBJ}?|;BRe@#;!2<5#Wso&%O`K_ZaYY;GBuS3{B!bVqEFJ7S}_-e{TFY0e}8yk=T?; ze+Tdk{0EKyDDc@|#@6oq<%3!w*tqow{g9R&o#QW!2JgQ zDe$0Ae?JYp5&l*lUjg0@%>E$r^H0G0fS)k&{|)#M@CJjIq094wi=#2N+)UpAei-$6 z*x+rz=XOG$3_laVGl+kYiGL07958zdOm7DGuLq*BeJ1`Ku_1Mttz!Cqk#e<$$Yjz(iMCO+3w-*j&zcB}Cp1HKROt^BLN zy^sgI)#}Do>b1B#0sq|+9(&P%U%xLJyUN7BA2@^ZZZ-HpVwCTCgTD&=-V@lPY101= z@Iy>b_yt`9J_&rSk?${oPXT94dd+7*|A4trOL?pWj$yCs0pouz@Lz9=#@LRKzZU_o zg}>&XQkMd61U_!!Uj@w78AM0;7L@|t4u5MO%D}t8pZ((Brd|Vl4D#3MwW+rQ?_+pF z?;hY3+6PU)O`QOKALJP~@&70AA%vec;lBqw1AM9YEAWB)U?NK>Px`;5Wi~j|4raSz;843ehNGTe2Kxo2IjmApvVU-RCDmZ%lNkd-wHf# z=$#Av&R3xRn*4VI-*P$jg&I5nT>5MzRxlpu^d15JEbLd+r1vQB zDfnCa`fK1PfWL0iTaF=Q>^;zTgI@$Z`~>Wcq}Qe{1pX-6+b z?HLw>fwu$e@VJmuQK%i19%Sjmxf={O^exoeFCxAa{!oL&v4)mXnnDTu9*xz1#2KXU_xApm9 z;H{|7x_-5(M}YI_Kj%&SCxGqvn(bX=CGv4!Bz6__nE5#a_$27z)fM6I3xR*&(~lnD zQ}9P{@gD=e_MS-WYli+cz}tQpiM`s$_XzM42>)vn{#M}Fdn2YjQ|cYS{_@-lycYge zA07nm0KX3y`VRrG_toE%z#9?%3r0Ra1>O$KaUJc)e-VEJ`efwO2ElG!i~45rcOGyz z?7ihzH}FgTBog~qlin_1n?DEr@qNG%^bhVd{z>2l)JJYiCI5~A??d`sf>F1D4*~1` z6=VrK13X~--w$l(U(Qs^)dRpk_+ljXdnSJ;faehY#U}jU0N)Dy7E`|O0N)90h89 z(HN#@rMyRgPr=`|FE;@}@FC!D8hkPE4Df##JOVri z{67p%0)H0rJX>&^Dgd7Y{l3iL8-Q(pknQD7z_%j4?k}M~1?;b1cLDz!+Mi()|HHul zjQ;dGqmQ2j=6o`|(ck|0Q{Mo-6ZAeQ;Sm=2!)RaW&-(fk;1529@sNrC3*h?@-paof z9sLu)w!e$bOX?xuQA2M%@O{4adMofrrf2xM2ly25g(mz2@DspRUvj|TM}P6K__wJW zfp?q}HTJ4ay%YG#Z$)BX#JGm_;ZJ~nj`8`33IB267}`r)zyBKeO^2efPZ|Gj0^9n= z^8O5XEyBOl-41*R;s2M(-}`{=&%wPRJrAWA8nxvYakdpIZrVC*5?p zQcdau`fxN#0le`&;Y-QEC)fg(wNH4^2kvJ}c-@;Ph)YBhg>NA9Hi5N#*_yVeoXyI6 z$$W})jxv>bPloZycZkVGWuP&fD{?f;JNNMrzFD2i24nNt@jB6QdLy>JSb`EtKPvM@ z=t_1gi=*?+gX>Y4^mLBL_Cc^+3a2%21Jxy$>>U~2J&^3dBYavc@5fSPekzgs?<#8c z2o4SM``eQT74|KlY&?`t&V@g7qJ^f4y(HML z0)|MzNosGldO1F{D_nOU4)C+112d30cBGaII6TEq&ho53oe#)Kc!<-H)KrFtrFc=g z)q$b?NqHSVIhiXaB|l?Bm#MMw{-o@=<@OwGO_OkZi$8flpH6Zqp6T-F6J0ffaFhi; zv@0ic=nXY{`v*pN-W3XS01U7A_=pdr%4QIo={=C@a0OXc$-%?m^zZa0pqhCPl52c)_qbqrK%J_QBY~CAnu4c7@-C5!q6o%xRm-{S1{C zya2}8Odf=?yR4=5UBS-_jn=BnTY5H-x5|+uPKZ_5&{WC#^K5CMsFVq|Ste(W>C+Ho ziyQXwXVnxAi6~U3{PDQ=aC+AN#8YJK6f(S}2=qxJS^_A2ws6!RYicTAtIYVHltOvz zcFQZ8bFd&s9#DWmkN!-?t>si%_W+_Xebf-P#Bwv3KdGV14!vKIRK*#6`LqZO4tdB9b;~6$zFdR=RO27N22>uQgz&*j6T6bhLLIa;V^ee zS$Qx7JTI3$xuPtTd@5hUek^SE^_PNCQk6pY1Vl1Xl>b788Zl5T9aq=ZDph{q5<7nJ zQP;%y_z28(Cdsxfm7m5J7^^e0m1Loa-E32Aiz-FCxwC@8Qz5 zd?7Z8&7{IUw0nZIWP+urJL%$4 z@&#<1j}ojeOg~*M=hc*}_*60}^giL*9<62`A(t11jlx5`zknUT{@ff*Rp#3mR?h>M z4joRWu%#SU5<4}M5=xuZ3XGMImzwG6fha*TImbNu)38z@r}ki%C0edBi~^44B%hR< znkcidCuqyjlB1=wRD|`~`l4CUUkRkVC4kG7DK%A?O`#LuWdtvbQ@E9Ez&?jXZ91If zI4eHe_<;V}Yz!uNhz;xuYnhw&!E$~O`~5Rne!fLCLJJhFfZpZL=*;BqVg|h)*d0${ z{7ooY-z0h+I57>idukp>r^2;LT3Fq?8ZNN)6gCbWnt;{87o(*~O!J#|=vcd)B-dzl zQ3s@JWmE*c%77UF#MWVtk6k#2imei5XSuw-dm^_|L3=g{5 zk!(xQ0|&!?v7%*Ir`lthjs%@=|zF{@V6Qy9ik7SQh0#Y#D zXOz;L%t_XhOw+Gu&`eem(N4ZK!|eNd2WSscdC{?e!j6*-T4b(;(7A*V!i@-c9O^&I zNnPv`CM)Ey6+0O;Fslt8TOFY|n3VyM?zfqyo*SwS4{hAbr78~~@kxA@!>u(C;snn6 z%FdUw}NtcfM15C~9)b)=iy3OHF`mF&lSq2oy zBu~TBqGVl!0rDPD0buEJseD4dRYk+)8>`T!!T9aRi5)lyl?G4}4pk+qI>I~D7Bsh@ zO9>XIGO0kuZBWA_*UFOhY)H@*WHZ8kL@1F;VLs=A-Hk4qJbqkaH@?Vqq%xSDO5tMS;pCRh-)$UiQz zg`s%IvsK-w>O;`xkjkZn;<3VjX}5;v&=vKK18rQ|A?XiH1*NQe%tkRyixDs(+FZK% z;!8#L1u@;v3LR*}1W9g4rcCN}oa*$YY%Zb4TH&W;pzY_J4Z?!R-~=rWjGfPpaLgUj z^5iRyCdcrJB$$u#Kpq`6ymx_jgV={kPU5XLUkk8>-_9&o*>D>5t(8hpG`v%YGH3Dj zqOJ9`J*@eGW_SMN0LJ{OfEi*5D6au_2Bk?c39$xMdkFfo3b-4|1mqF;z#i9<+r22MUyicmMzZ diff --git a/org.gridsite.core/src/roffit b/org.gridsite.core/src/roffit deleted file mode 100755 index d1c7263..0000000 --- a/org.gridsite.core/src/roffit +++ /dev/null @@ -1,370 +0,0 @@ -#!/usr/bin/env perl -# -# roffit: convert man page source files to HTML -# -# Read an nroff file. Output a HTML file. -# -# This is a very simple script, but I use it on very simple man pages and I've -# found no other script that makes beautiful web pages. -# -my $version = "0.3"; # (14 November 2003) -# Author: Daniel Stenberg -# Please email me improvements. -# -# You're free to do whatever you want with this script. -# -# Changes: -# -# 0.3 - Daniel Fandrich brought: -# o deal with .lp lines -# o .TH needs no section portion anymore -# o added generator meta tag in the header -# -# 0.2 - fixed the name for the SH section -# - added links from all words within \fIthis\fP or \fBthis\fP -# that has the same text as a .SH or .IP. -# - -use strict; -#use warnings; - -my $InFH = \*STDIN; -my $OutFH = \*STDOUT; -my $debugFH = \*STDERR; - -my %manpage; -my @out; - -my $indentlevel=0; # logical levels, not columns -my @p; -my $within_tp; -my $standalone=1; # by default we make stand-alone HTML pages -my $pre; -my %anchor; # hash with all anchors - -while($ARGV[0]) { - if($ARGV[0] eq "--bare") { - # don't include headers and stuff - $standalone=0; - shift @ARGV; - } - else { - printf $debugFH "unknown option: %s\n", $ARGV[0] if($ARGV[0] ne "-h"); - print $debugFH "Usage: roffit [options] < infile > outfile\n", - "Options:\n", - " --bare Do not put in HTML, HEAD, BODY tags\n"; - exit; - } -} - -sub showp { - my @p = @_; - push @out, "\n

", @p; -} - -sub defaultcss { - print $OutFH < -P.level0 { - padding-left: 2em; -} - -P.level1 { - padding-left: 4em; -} - -P.level2 { - padding-left: 6em; -} - -span.emphasis { - font-style: italic; -} - -span.bold { - font-weight: bold; -} - -span.manpage { - font-weight: bold; -} - -h2.nroffsh { - background-color: #e0e0e0; -} - -span.nroffip { - font-weight: bold; - font-size: 120%; - font-family: monospace; -} - -p.roffit { - text-align: center; - font-size: 80%; -} - -ENDOFCSS - ; -} - -sub text2name { - my ($text) = @_; - $text =~ s/^ *([^ ]*).*/$1/g; - $text =~ s/[^a-zA-Z0-9-]//g; - return $text; -} - -# scan through the file and check for sections we should convert -# to proper links -sub linkfile { - my @new; - for(@out) { - my $line=$_; - my $l; - while($line =~ s/([^<]*)<\/span>/[]/) { - my ($style, $name)=($1, $2); - - $l = text2name($name); - - #printf $debugFH "$style - $name - %s - %d\n", - #$l, $anchor{$l}; - - my $link; - if($anchor{$l}) { - $link="$name"; - } - else { - $link="$name"; - } - $line =~ s/\[\]/$link/; - } - push @new, $line; - } - return @new; -} - -sub parsefile { - - while(<$InFH>) { - my $in = $_; - my $out; - # print $debugFH "DEBUG IN: $_"; - - $in =~ s/[\r\n]//g if(!$pre); # tear off newlines - - if($in =~ /^\.([^ \n]*)(.*)/) { - # this is a line starting with a dot, that means it is special - my ($keyword, $rest) = ($1, $2); - $out = ""; - - # cut off initial spaces - $rest =~ s/^ +//g; - - if($keyword eq "\\\"") { - # this is a comment, skip this line - } - elsif($keyword =~ /^TH$/i) { - # man page header: - # curl 1 "22 Oct 2003" "Curl 7.10.8" "Curl Manual" - # NAME SECTION DATE VERSION MANUAL - if($rest =~ /([^ ]*) (\d+) \"([^\"]*)\" \"([^\"]*)\"(\"([^\"]*)\")?/) { - # strict matching only so far - $manpage{'name'} = $1; - $manpage{'section'} = $2; - $manpage{'date'} = $3; - $manpage{'version'} = $4; - $manpage{'manual'} = $6; - } - } - elsif($keyword =~ /^SH$/i) { - # Section Header - showp(@p); - @p=""; - if($pre) { - push @out, "\n"; - $pre = 0; - } - - my $name = text2name($rest); - $anchor{$name}=1; - - $rest =~ s/\"//g; # cut off quotes - $rest =~ s//>/g; - $out = "

$rest

"; - $indentlevel=0; - $within_tp=0; - } - elsif(($keyword =~ /^B$/i) || ($keyword =~ /^BI$/i)) { - # Make B and BI the same for simplicity - $rest =~ s/\"//g; # cut off quotes - $rest =~ s//>/g; - push @p, "$rest "; - } - elsif($keyword =~ /^I$/i) { - $rest =~ s/\"//g; # cut off quotes - $rest =~ s//>/g; - push @p, "$rest "; - } - elsif($keyword =~ /^RS$/i) { - # the start of another indent-level. for inlined tables - # within an "IP" - showp(@p); - @p=""; - $indentlevel++; - } - elsif($keyword =~ /^RE$/i) { - # end of the RS section - showp(@p); - @p=""; - $indentlevel--; - } - elsif($keyword =~ /^NF$/i) { - # We let nf start a
 section
-                showp(@p);
-                @p="";
-                push @out, "
\n";
-                $pre=1
-            }
-            elsif($keyword =~ /^TP$/i) {
-                # Used within an "RS" section to make a new line. The first
-                # TP as a column indicator, but we decide to do that
-                # controlling in the CSS instead.
-                $within_tp=1;
-                showp(@p);
-                @p="";                
-            }
-            elsif($keyword =~ /^IP$/i) {
-                # start of a new paragraph coming up
-                showp(@p);
-                @p="";
-
-                my $name= text2name($rest);
-                $anchor{$name}=1;
-
-                $rest =~ s/\"//g; # cut off quotes
-                $rest =~ s//>/g;
-                
-                $indentlevel-- if ($indentlevel);
-                push @p, "$rest ";
-                # make this a single-line title
-                showp(@p);
-                @p="";
-                $indentlevel++;
-                $within_tp=0;
-            }
-            elsif($keyword =~ /^ad$/i) {
-                showp(@p);
-                @p="";
-            }
-            elsif($keyword =~ /^sp$/i) {
-                showp(@p);
-                @p="";
-            }
-            elsif($keyword =~ /^lp$/i) {
-                # marks end of a paragraph
-                showp(@p);
-                @p="";
-            }
-            elsif($keyword =~ /^pp$/i) {
-                # PP ends a TP section, but some TP sections don't use it
-                $within_tp=0;
-            }
-            elsif($keyword =~ /^so$/i) {
-                # This keyword refers to a different man page, named in the
-                # $rest.
-                # We don't support this
-                push @out, "See the $rest man page.\n";
-            }
-            elsif($keyword =~ /^BR$/i) {
-                # I'm not sure what this does exactly, but this is commonly
-                # used to include pointers to other man pages. Let's assume
-                # it only does that for now.
-                # blabla (3)
-                # or "blabla (3)"
-                # or strcmp "(3), " strcasecmp "(3)"
-                # etc
-                
-                $rest =~ s/\"//g; # cut off quotes
-                my @all = split /,/, $rest;
-                for(@all) {
-                    if(/([^ ]*) *\((\d+)\)/) {
-                        # TODO: this looks like a man page, check if there's a
-                        # HTML file for it and if so make a link to it
-                    }
-
-                    push @p, "$_ ";
-                }
-            }
-            else {
-                showp(@p);
-                print $debugFH "ALERT: unknown keyword \"$keyword\"\n";
-            }
-        }
-        else {
-            # text line, decode \-stuff
-            my $txt = $in;
-
-            $txt =~ s//>/g;
-            $txt =~ s/\\&//g; # cut off \&
-            $txt =~ s/\\fI//g;
-            $txt =~ s/\\fB//g;
-            $txt =~ s/\\fP/<\/span>/g;
-            $txt =~ s/\\//g;
-
-            if($txt =~ /^[ \t\r\n]*$/) {
-                # no contents, marks end of a paragraph
-                showp(@p);
-                @p="";
-            }
-            else {
-                $txt =~ s/^ /\ \;/g;
-                push @p, "$txt ";
-            }
-            $out ="";
-        }
-
-        if($out) {
-            push @out, $out;
-   #         print $debugFH "DEBUG OUT: $out\n";
-        }
-        else {
-   #         print $debugFH "DEBUG OUT: [withheld]\n";
-        }
-    }
-    showp(@p);
-}
-
-parsefile();
-
-my @conv = linkfile();
-
-my $title=sprintf("%s man page",
-                  $manpage{'name'}?$manpage{'name'}:"secret");
-
-if($standalone) {
-    print $OutFH <
-$title
-
-MOO
-    ;
-    defaultcss();
-    print "\n";
-}
-
-print $OutFH @conv;
-print $OutFH <
- This HTML page was made with roffit.
-ROFFIT
-    ;
-
-if($standalone) {
-    print "\n";
-}
diff --git a/org.gridsite.core/src/urlencode.c b/org.gridsite.core/src/urlencode.c
deleted file mode 100644
index bea36a9..0000000
--- a/org.gridsite.core/src/urlencode.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
-   Copyright (c) 2002-3, Andrew McNab, University of Manchester
-   All rights reserved.
-
-   Redistribution and use in source and binary forms, with or
-   without modification, are permitted provided that the following
-   conditions are met:
-
-     o Redistributions of source code must retain the above
-       copyright notice, this list of conditions and the following
-       disclaimer. 
-     o Redistributions in binary form must reproduce the above
-       copyright notice, this list of conditions and the following
-       disclaimer in the documentation and/or other materials
-       provided with the distribution. 
-
-   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
-   CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
-   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-   MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
-   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
-   BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
-   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
-   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
-   OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
-   OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
-   POSSIBILITY OF SUCH DAMAGE.
-*/
-
-/*---------------------------------------------------------------*
- * For more about GridSite: http://www.gridsite.org/             *
- *---------------------------------------------------------------*/
-
-#include 
-#include 
-
-#include "gridsite.h"
-
-int main(int argn, char *argv[])
-{
-  int    i;
-
-  if (argn == 1)
-    {
-      puts("urlencode [-m|-d] string-to-encode-or-decode");
-      return 0;
-    }
-
-  if      (strcmp(argv[1], "-d") == 0) /* decode */
-   for (i = 2; i < argn; ++i) 
-      {
-        if (i > 2) fputs(" ", stdout);
-        fputs(GRSThttpUrlDecode(argv[i]), stdout);
-      }
-  else if (strcmp(argv[1], "-m") == 0) /* mild encode */
-   for (i = 2; i < argn; ++i) 
-      {
-        if (i > 2) fputs("%20", stdout);
-        fputs(GRSThttpUrlMildencode(argv[i]), stdout);
-      }
-  else /* standard encode */
-   for (i = 1; i < argn; ++i) 
-      {
-        if (i > 1) fputs("%20", stdout);
-        fputs(GRSThttpUrlEncode(argv[i]), stdout);
-      }
-
-  puts("");
-
-  return 0;
-}
-- 
1.8.2.3

This release fixes the -following bugs and issues. Since there are no previous public releases, this -list refers to the previous development release. Bug numbers refer to the gLite -Bug Tracking system database hosted on the CERN Savannah system at https://savannah.cern.ch/bugs/?group=jra1mdw