diff --git a/CMakeLists.txt b/CMakeLists.txt index d9124e6..bec9bbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -4,7 +4,7 @@ project(davrods C) set(IRODS_VERSION "4.2.1" CACHE STRING "iRODS client library version") -set(DAVRODS_VERSION "${IRODS_VERSION}_1.1.1") +set(DAVRODS_VERSION "${IRODS_VERSION}_1.2.0") find_program(APXS apxs DOC "Apache/HTTPD extension tool location") if(NOT APXS) @@ -88,6 +88,7 @@ if(INSTALLABLE_ON_THIS_SYSTEM) RENAME 10-davrods.conf) install(FILES davrods-vhost.conf + davrods-anonymous-vhost.conf DESTINATION /etc/httpd/conf.d/) install(FILES irods_environment.json @@ -132,6 +133,7 @@ if(INSTALLABLE_ON_THIS_SYSTEM) "%doc /usr/share/doc/davrods-${DAVRODS_VERSION}/COPYING.LESSER" "%config(noreplace) /etc/httpd/conf.modules.d/10-davrods.conf" "%config(noreplace) /etc/httpd/conf.d/davrods-vhost.conf" + "%config(noreplace) /etc/httpd/conf.d/davrods-anonymous-vhost.conf" "%config(noreplace) /etc/httpd/irods/irods_environment.json" "%attr(700,apache,apache) /var/lib/davrods") diff --git a/README.md b/README.md index 900ed44..1f0da5e 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Notable features include: - Supports PAM and Native (a.k.a. STANDARD) iRODS authentication. - Supports SSL encryption for the entire iRODS connection. - Easy to configure using Apache configuration directives. +- Supports an anonymous access mode for password-less public access. - Supports iRODS server versions 4+ and is backwards compatible with 3.3.1. ## Download ## @@ -21,7 +22,7 @@ Notable features include: There are currently two supported Davrods versions: - [`davrods-4.1_1.1.1`](https://github.com/UtrechtUniversity/davrods/releases/tag/4.1_1.1.1), branch `irods-4.1-libs` -- [`davrods-4.2.1_1.1.1`](https://github.com/UtrechtUniversity/davrods/releases/tag/4.2.1_1.1.1), branch `master` +- [`davrods-4.2.1_1.2.0`](https://github.com/UtrechtUniversity/davrods/releases/tag/4.2.1_1.2.0), branch `master` The left side of the version number indicates the version of the iRODS client libraries that Davrods uses. @@ -81,11 +82,25 @@ icommands. ### HTTPD vhost configuration ### -The Davrods RPM distribution installs a commented out vhost template -in `/etc/httpd/conf.d/davrods-vhost.conf`. With the comment marks -(`#`) removed, this provides you with a sane default configuration -that you can tune to your needs. All Davrods configuration options are -documented in this file and can be changed to your liking. +The Davrods RPM distribution installs two vhost template files: + +1. `/etc/httpd/conf.d/davrods-vhost.conf` +2. `/etc/httpd/conf.d/davrods-anonymous-vhost.conf` + +These files are provided completely commented out. To enable either +configuration, simply remove the first column of `#` signs, and then +tune the settings to your needs. + +The normal vhost configuration (1) provides sane defaults for +authenticated access. + +The anonymous vhost configuration (2) allows password-less public +access using the `anonymous` iRODS account. + +You can enable both configurations simultaneously, as long as their +ServerName values are unique (for example, you might use +`dav.example.com` for authenticated access and +`public.dav.example.com` for anonymous access). ### The iRODS environment file ### @@ -180,7 +195,8 @@ For this reason you will need to install the files manually: - Copy `mod_davrods.so` to your Apache module directory. - Copy `davrods.conf` to your Apache module configuration/load directory. -- Copy `davrods-vhost.conf` to your Apache vhost configuration directory. +- Copy `davrods-vhost.conf` and `davrods-anonymous-vhost.conf` to your + Apache vhost configuration directory. - Create an `irods` directory in a location where Apache HTTPD has read access. - Copy `irods_environment.json` to the `irods` directory. diff --git a/auth.c b/auth.c index c5b76d7..26f9b30 100644 --- a/auth.c +++ b/auth.c @@ -99,6 +99,13 @@ static int do_rods_login_pam( /** * \brief Connect to iRODS and attempt to login. + * + * \param[in] r request record + * \param[in] username + * \param[in] password + * \param[out] rods_conn will be filled with the new iRODS connection, if auth is succesful. + * + * \return An authn status code, AUTH_GRANTED if succesful. */ static authn_status rods_login( request_rec *r, @@ -151,11 +158,11 @@ static authn_status rods_login( // Whether to use SSL for the entire connection. // Note: SSL is always in effect during PAM auth, regardless of negotiation results. - bool useSsl = false; + bool use_ssl = false; if ((*rods_conn)->negotiation_results && !strcmp((*rods_conn)->negotiation_results, "CS_NEG_USE_SSL")) { - useSsl = true; + use_ssl = true; } else { // Negotiation was disabled or resulted in CS_NEG_USE_TCP (i.e. no SSL). } @@ -163,7 +170,7 @@ static authn_status rods_login( ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "SSL negotiation result: <%s>: %s", (*rods_conn)->negotiation_results, - useSsl + use_ssl ? "will use SSL for the entire connection" : "will NOT use SSL (if using PAM, SSL will only be used during auth)" ); @@ -173,7 +180,7 @@ static authn_status rods_login( " (ignore ssl_on, it seems 4.x does not update it after SSL is turned on automatically during rcConnect)", (*rods_conn)->ssl?1:0, (*rods_conn)->ssl_on); - if (useSsl) { + if (use_ssl) { // Verify that SSL is in effect in compliance with the // negotiation result, to prevent any unencrypted // information (password or data) to be sent in the clear. @@ -190,7 +197,7 @@ static authn_status rods_login( // If the negotiation result requires plain TCP, but we are // using the PAM auth scheme, we need to turn on SSL during // auth. - if (!useSsl && conf->rods_auth_scheme == DAVRODS_AUTH_PAM) { + if (!use_ssl && conf->rods_auth_scheme == DAVRODS_AUTH_PAM) { if ((*rods_conn)->ssl) { // This should not happen. // In this situation we don't know if we should stop @@ -267,7 +274,7 @@ static authn_status rods_login( // Disable SSL if it was in effect during auth but negotiation (or lack // thereof) demanded plain TCP for the rest of the connection. - if (!useSsl && (*rods_conn)->ssl) { + if (!use_ssl && (*rods_conn)->ssl) { ap_log_rerror(APLOG_MARK, APLOG_DEBUG, APR_SUCCESS, r, "Disabling SSL (was used for PAM only)"); @@ -306,7 +313,7 @@ static authn_status rods_login( return result; } -static authn_status check_rods(request_rec *r, const char *username, const char *password) { +authn_status check_rods(request_rec *r, const char *username, const char *password) { int status; // Obtain davrods directory config. @@ -343,7 +350,7 @@ static authn_status check_rods(request_rec *r, const char *username, const char if (status || !pool) { ap_log_rerror(APLOG_MARK, APLOG_ERR, status, r, - "Could not create davrods apr pool"); + "Could not create Davrods apr pool"); return HTTP_INTERNAL_SERVER_ERROR; } diff --git a/auth.h b/auth.h index 67318f6..44d861b 100644 --- a/auth.h +++ b/auth.h @@ -23,6 +23,9 @@ #define _RODS_AUTH_H #include "mod_davrods.h" +#include + +authn_status check_rods(request_rec *r, const char *username, const char *password); void davrods_auth_register(apr_pool_t *p); diff --git a/common.c b/common.c index 988da3b..e3dfb6c 100644 --- a/common.c +++ b/common.c @@ -46,21 +46,6 @@ const char *get_rods_error_msg(int rods_error_code) { return rodsErrorName(rods_error_code, &submsg); } -/** - * \brief Extract the davrods pool from a request, as set by the rods_auth component. - * - * \param r an apache request record. - * - * \return the davrods memory pool - */ -apr_pool_t *get_davrods_pool_from_req(request_rec *r) { - // TODO: Remove function, move apr call to the single caller. - apr_pool_t *pool = NULL; - int status = apr_pool_userdata_get((void**)&pool, "davrods_pool", r->connection->pool); - assert(status == 0); - return pool; -} - // }}} // DAV provider definition and registration {{{ diff --git a/common.h b/common.h index 115c3a1..1a7525f 100644 --- a/common.h +++ b/common.h @@ -40,15 +40,6 @@ */ const char *get_rods_error_msg(int rods_error_code); -/** - * \brief Extract the davrods pool from a request, as set by the rods_auth component. - * - * \param r an apache request record. - * - * \return the davrods memory pool - */ -apr_pool_t *get_davrods_pool_from_req(request_rec *r); - void davrods_dav_register(apr_pool_t *p); #endif /* _DAVRODS_COMMON_H_ */ diff --git a/config.c b/config.c index 55d38a5..a9e94d3 100644 --- a/config.c +++ b/config.c @@ -53,25 +53,33 @@ void *davrods_create_dir_config(apr_pool_t *p, char *dir) { conf->rods_default_resource = ""; conf->rods_env_file = "/etc/httpd/irods/irods_environment.json"; conf->rods_auth_scheme = DAVRODS_AUTH_NATIVE; + // Default to having the user's home directory as the exposed root // because that collection is more or less guaranteed to be readable by // the current user (as opposed to the //home directory, which - // seems to be hidden for rodsusers by default). + // is hidden for rodsusers by default). conf->rods_exposed_root = "User"; // NOTE: Keep this in sync with the option below. conf->rods_exposed_root_type = DAVRODS_ROOT_USER_DIR; + // Default to 4 MiB buffer sizes, which is a good balance + // between resource usage and transfer performance in common + // setups. conf->rods_tx_buffer_size = 4 * 1024 * 1024; conf->rods_rx_buffer_size = 4 * 1024 * 1024; - conf->tmpfile_rollback = DAVRODS_TMPFILE_ROLLBACK_NO; + conf->tmpfile_rollback = DAVRODS_TMPFILE_ROLLBACK_OFF; conf->locallock_lockdb_path = "/var/lib/davrods/lockdb_locallock"; + conf->anonymous_mode = DAVRODS_ANONYMOUS_MODE_OFF; + conf->anonymous_auth_username = "anonymous"; + conf->anonymous_auth_password = ""; + // Use the minimum PAM temporary password TTL. We // re-authenticate using PAM on every new HTTP connection, so // there's no use keeping the temporary password around for // longer than the maximum keepalive time. (We don't ever use // a temporary password more than once). - conf->rods_auth_ttl = 1; // In hours. + conf->rods_auth_ttl = 1; // In hours. } return conf; } @@ -107,6 +115,10 @@ void *davrods_merge_dir_config(apr_pool_t *p, void *_parent, void *_child) { DAVRODS_PROP_MERGE(tmpfile_rollback); DAVRODS_PROP_MERGE(locallock_lockdb_path); + DAVRODS_PROP_MERGE(anonymous_mode); + DAVRODS_PROP_MERGE(anonymous_auth_username); + DAVRODS_PROP_MERGE(anonymous_auth_password); + assert(set_exposed_root(conf, exposed_root) >= 0); #undef DAVRODS_PROP_MERGE @@ -258,12 +270,12 @@ static const char *cmd_davrodstmpfilerollback( ) { davrods_dir_conf_t *conf = (davrods_dir_conf_t*)config; - if (!strcasecmp(arg1, "yes")) { - conf->tmpfile_rollback = DAVRODS_TMPFILE_ROLLBACK_YES; - } else if (!strcasecmp(arg1, "no")) { - conf->tmpfile_rollback = DAVRODS_TMPFILE_ROLLBACK_NO; + if (!strcasecmp(arg1, "on") || !strcasecmp(arg1, "yes")) { + conf->tmpfile_rollback = DAVRODS_TMPFILE_ROLLBACK_ON; + } else if (!strcasecmp(arg1, "off") || !strcasecmp(arg1, "no")) { + conf->tmpfile_rollback = DAVRODS_TMPFILE_ROLLBACK_OFF; } else { - return "This directive accepts only 'Yes' and 'No' values"; + return "This directive accepts only 'On' and 'Off' values"; } return NULL; @@ -280,6 +292,45 @@ static const char *cmd_davrodslockdb( return NULL; } +static const char *cmd_davrodsanonymousmode( + cmd_parms *cmd, void *config, + const char *arg1 +) { + davrods_dir_conf_t *conf = (davrods_dir_conf_t*)config; + + if (!strcasecmp(arg1, "on")) { + conf->anonymous_mode = DAVRODS_ANONYMOUS_MODE_ON; + } else if (!strcasecmp(arg1, "off")) { + conf->anonymous_mode = DAVRODS_ANONYMOUS_MODE_OFF; + } else { + return "This directive accepts only 'On' and 'Off' values"; + } + + return NULL; +} + +static const char *cmd_davrodsanonymouslogin( + cmd_parms *cmd, void *config, + int argc, char * const *argv +) { + davrods_dir_conf_t *conf = (davrods_dir_conf_t*)config; + + if (argc < 1 || argc > 2) + return "Specify a username and optionally a password"; + + if (!strlen(argv[0])) + return "Username must not be empty"; + + conf->anonymous_auth_username = argv[0]; + + if (argc == 2) + conf->anonymous_auth_password = argv[1]; + else + conf->anonymous_auth_password = ""; + + return NULL; +} + // }}} const command_rec davrods_directives[] = { @@ -327,6 +378,14 @@ const command_rec davrods_directives[] = { DAVRODS_CONFIG_PREFIX "LockDB", cmd_davrodslockdb, NULL, ACCESS_CONF, "Lock database location, used by the davrods-locallock DAV provider" ), + AP_INIT_TAKE1( + DAVRODS_CONFIG_PREFIX "AnonymousMode", cmd_davrodsanonymousmode, + NULL, ACCESS_CONF, "Anonymous mode On/Off switch" + ), + AP_INIT_TAKE_ARGV( + DAVRODS_CONFIG_PREFIX "AnonymousLogin", cmd_davrodsanonymouslogin, + NULL, ACCESS_CONF, "Anonymous mode auth method, username and optional password" + ), { NULL } }; diff --git a/config.h b/config.h index 24ed941..94ab893 100644 --- a/config.h +++ b/config.h @@ -39,8 +39,8 @@ typedef struct { enum { // Need to have something other than a bool to recognize an 'unset' state. - DAVRODS_TMPFILE_ROLLBACK_YES = 1, - DAVRODS_TMPFILE_ROLLBACK_NO, + DAVRODS_TMPFILE_ROLLBACK_OFF = 1, + DAVRODS_TMPFILE_ROLLBACK_ON, } tmpfile_rollback; const char *locallock_lockdb_path; @@ -50,6 +50,14 @@ typedef struct { DAVRODS_AUTH_PAM, } rods_auth_scheme; + enum { + DAVRODS_ANONYMOUS_MODE_OFF = 1, + DAVRODS_ANONYMOUS_MODE_ON, + } anonymous_mode; + + const char *anonymous_auth_username; + const char *anonymous_auth_password; + int rods_auth_ttl; // In hours. enum { @@ -58,7 +66,7 @@ typedef struct { DAVRODS_ROOT_CUSTOM_DIR = 1, // => DAVRODS_ROOT_ZONE_DIR, // Zone => / DAVRODS_ROOT_HOME_DIR, // Home => //home (not the user's home collection!) - DAVRODS_ROOT_USER_DIR, // User => //home/ + DAVRODS_ROOT_USER_DIR, // User => //home/ } rods_exposed_root_type; } davrods_dir_conf_t; diff --git a/davrods-anonymous-vhost.conf b/davrods-anonymous-vhost.conf new file mode 100644 index 0000000..5def30b --- /dev/null +++ b/davrods-anonymous-vhost.conf @@ -0,0 +1,181 @@ +## -*- mode: apache -*- +## vim: ft=apache ts=4 sw=4 et +## +## davrods-anonymous-vhost.conf +## +## Davrods is a mod_dav WebDAV provider. Configuration directives for +## Davrods should be placed in a block. +## +## Below we provide an example vhost configuration that enables Davrods +## in anonymous access mode. See the file 'davrods-vhost.conf' for a +## vhost configuration *with* authentication. +## +## Note that in order to use anonymous access, your iRODS permissions +## need to be set correctly as well: +## 1) Create the anonymous user if it doesn't yet exist (or use a +## different user - see option DavRodsAnonymousLogin) +## 2) Grant read/write/own access to anonymous where appropriate +## 3) Point the DavRodsExposedRoot to a location where the anonymous +## user has at least 'read' access. +## +# +# +# # Enter your server name here. +# ServerName public.dav.example.com +# +# # NB: Some webdav clients expect the server to implement webdav at the root +# # location (they execute an OPTIONS request to verify existence of webdav +# # protocol support). +# +# +# +# # Options needed to enable Davrods. {{{ +# # ================================= +# +# # Disable built-in Apache directory listings - Davrods will +# # provide this instead. +# DirectoryIndex disabled +# +# # Don't restrict access on the HTTP side - auth must be +# # disabled for anonymous access to work. +# AuthType None +# Require all granted +# +# # The DAV provider for this location. +# # +# # Davrods implements multiple dav providers, use either: +# # - davrods-nolocks: WebDAV class 1 provider, no support for locking +# # - davrods-locallock (recommended): WebDAV class 2 provider, uses a DBM lock database local to this webserver +# # +# # Note that the davrods-locallock provider requires an apache-writable lockdb directory +# # (/var/lib/davrods, or a path specified using the DavRodsLockDB directive - see further down this file). +# # The RPM distribution creates this directory for you. +# # +# Dav davrods-locallock +# +# # }}} +# +# # Davrods configuration directives. {{{ +# # ================================= +# +# # Location of the iRODS environment file that specifies the iRODS +# # client configuration used by Davrods. +# # +# # Note: When options in the iRODS environment file overlap with Davrods +# # configuration directives, as with the host, port, and zone of the +# # iRODS server, the values specified in the iRODS environment file are +# # NOT used. +# # +# DavRodsEnvFile /etc/httpd/irods/irods_environment.json +# +# # The following options can be used to customize Davrods for your environment. +# # These options and their default values are provided below. +# # Having these directives commented out has the effect of enabling +# # the listed default option. +# +# # Hostname and port of the iRODS server to connect to. +# # +# #DavRodsServer localhost 1247 +# +# # Data grid zone id of the iRODS server. +# # +# #DavRodsZone tempZone +# +# # Authentication type to use when connecting to iRODS. +# # +# # Supported authentication types are 'Native' and 'Pam'. +# # ('Native' corresponds to what was formerly called 'Standard' auth in iRODS). +# # +# #DavRodsAuthScheme Native +# +# # Anonymous mode switch. +# # +# # (default: Off) +# # When 'Off', basic authentication is required to log into +# # Davrods. AuthType must be set to 'Basic' and AuthBasicProvider +# # must be set to 'irods'. There must also be a 'Require valid-user' +# # line. +# # +# # When 'On', Davrods will log into iRODS with a preset +# # username and password (See options DavRodsAnonymousLogin and +# # DavRodsAuthScheme). AuthType must be unset, or set to None, +# # and there should be no 'Require valid-user' line +# # (instead: Require all granted). +# # +# # This allows users to access Davrods without being prompted +# # for a login, making public access and embedding in web pages +# # easier. +# DavRodsAnonymousMode On +# +# # iRODS authentication options for Davrods anonymous mode. +# # +# # This option is used only when DavRodsAnonymousMode is set to +# # 'On'. +# # +# # Specifies the username and password to use for anonymous login. +# # The default value is 'anonymous', with an empty password. +# # (this user, if created, is treated specially within iRODS) +# # +# # The special 'anonymous' iRODS user normally requires the +# # DavRodsAuthScheme to be set to Native. +# # +# DavRodsAnonymousLogin "anonymous" "" +# +# # iRODS default resource to use for file uploads. +# # +# # Leave this empty to let the server decide. +# # +# #DavRodsDefaultResource "" +# +# # Exposed top collection of iRODS. +# # +# # Note that the collection chosen MUST be readable for all users, +# # otherwise they will experience problems when mounting the drive. +# # For example, if you set it to "Home", then as a rodsadmin user +# # execute the icommand: ichmod read public /zone-name/home +# # +# # Davrods accepts the following values for exposed-root: +# # - 'Zone' (collection /zone-name) +# # - 'Home' (collection /zone-name/home) +# # - 'User' (collection /zone-name/home/logged-in-username) +# # - full-path (named collection, must be absolute path, starts with /) +# # +# #DavRodsExposedRoot User +# +# # Size of the buffers used for file transfer to/from the iRODS server. +# # +# # The default values optimize performance for regular configurations. +# # The Tx buffer is used for transfer to iRODS (PUT), while the Rx +# # buffer is used for transfer from iRODS (GET). +# # Buffer sizes lower than 1024K will lead to decreased file transfer performance. +# # +# # The buffer sizes are specified as a number of kibibytes ('1' means 1024 bytes). +# # We use 4 MiB transfer buffers by default. +# # +# #DavRodsTxBufferKbs 4096 +# #DavRodsRxBufferKbs 4096 +# +# # Optionally Davrods can support rollback for aborted uploads. In this scenario +# # a temporary file is created during upload and upon succesful transfer this +# # temporary file is renamed to the destination filename. +# # NB: Please note that the use of temporary files may conflict with your iRODS +# # data policies (e.g. a acPostProcForPut would act upon the temporary filename). +# # Valid values for this option are 'On'/'Yes' and 'Off'/'No'. +# # +# #DavRodsTmpfileRollback Off +# +# # When using the davrods-locallock DAV provider (see the 'Dav' +# # directive above), this option can be used to set the location of the +# # lock database. +# # +# #DavRodsLockDB /var/lib/davrods/lockdb_locallock +# +# # }}} +# +# +# +# # We strongly recommend to enable Davrods only over SSL. +# # For HTTPS-only access, change the port at the start of the vhost block +# # from 80 to 443 and add your SSL options below. +# +# diff --git a/davrods-vhost.conf b/davrods-vhost.conf index 0d52065..80bca9e 100644 --- a/davrods-vhost.conf +++ b/davrods-vhost.conf @@ -1,15 +1,18 @@ -# davrods-vhost.conf -# -# davrods is a mod_dav WebDAV provider. Configuration directives for davrods -# should be placed in a block. -# -# Below we provide an example vhost configuration that enables davrods using -# its default options. -# +## -*- mode: apache -*- +## vim: ft=apache ts=4 sw=4 et +## +## davrods-vhost.conf +## +## Davrods is a mod_dav WebDAV provider. Configuration directives for +## Davrods should be placed in a block. +## +## Below we provide an example vhost configuration that enables Davrods +## using its default options. +## # # # # Enter your server name here. -# ServerName www.example.com +# ServerName dav.example.com # # # NB: Some webdav clients expect the server to implement webdav at the root # # location (they execute an OPTIONS request to verify existence of webdav @@ -17,10 +20,11 @@ # # # -# # Options needed to enable davrods. {{{ +# # Options needed to enable Davrods. {{{ # # ================================= # -# # Disable built-in directory listings. +# # Disable built-in Apache directory listings - Davrods will +# # provide this instead. # DirectoryIndex disabled # # # Restrict access to authenticated users. @@ -30,14 +34,12 @@ # # The realm name that will be shown to clients upon authentication # AuthName DAV # -# # Use the 'irods' HTTP basic authentication provider, implemented by -# # davrods. This provider is used for setting up the iRODS connection, -# # and is therefore required for davrods to function. +# # Use the 'irods' HTTP basic authentication provider, implemented by Davrods. # AuthBasicProvider irods # # # The DAV provider for this location. # # -# # davrods implements multiple dav providers, use either: +# # Davrods implements multiple dav providers, use either: # # - davrods-nolocks: WebDAV class 1 provider, no support for locking # # - davrods-locallock (recommended): WebDAV class 2 provider, uses a DBM lock database local to this webserver # # @@ -49,11 +51,11 @@ # # # }}} # -# # davrods configuration directives. {{{ +# # Davrods configuration directives. {{{ # # ================================= # # # Location of the iRODS environment file that specifies the iRODS -# # client configuration used by davrods. +# # client configuration used by Davrods. # # # # Note: When options in the iRODS environment file overlap with Davrods # # configuration directives, as with the host, port, and zone of the @@ -62,7 +64,7 @@ # # # DavRodsEnvFile /etc/httpd/irods/irods_environment.json # -# # The following options can be used to customize davrods for your environment. +# # The following options can be used to customize Davrods for your environment. # # These options and their default values are provided below. # # Having these directives commented out has the effect of enabling # # the listed default option. @@ -82,6 +84,39 @@ # # # #DavRodsAuthScheme Native # +# # Anonymous mode switch. +# # +# # (default: Off) +# # When 'Off', basic authentication is required to log into +# # Davrods. AuthType must be set to 'Basic' and AuthBasicProvider +# # must be set to 'irods'. There must also be a 'Require valid-user' +# # line. +# # +# # When 'On', Davrods will log into iRODS with a preset +# # username and password (See options DavRodsAnonymousLogin and +# # DavRodsAuthScheme). AuthType must be unset, or set to None, +# # and there should be no 'Require valid-user' line +# # (instead: Require all granted). +# # +# # This allows users to access Davrods without being prompted +# # for a login, making public access and embedding in web pages +# # easier. +# #DavRodsAnonymousMode Off +# +# # iRODS authentication options for Davrods anonymous mode. +# # +# # This option is used only when DavRodsAnonymousMode is set to +# # 'On'. +# # +# # Specifies the username and password to use for anonymous login. +# # The default value is 'anonymous', with an empty password. +# # (this user, if created, is treated specially within iRODS) +# # +# # The special 'anonymous' iRODS user normally requires the +# # DavRodsAuthScheme to be set to Native. +# # +# #DavRodsAnonymousLogin "anonymous" "" +# # # iRODS default resource to use for file uploads. # # # # Leave this empty to let the server decide. @@ -116,14 +151,14 @@ # #DavRodsTxBufferKbs 4096 # #DavRodsRxBufferKbs 4096 # -# # Optionally davrods can support rollback for aborted uploads. In this scenario +# # Optionally Davrods can support rollback for aborted uploads. In this scenario # # a temporary file is created during upload and upon succesful transfer this # # temporary file is renamed to the destination filename. # # NB: Please note that the use of temporary files may conflict with your iRODS # # data policies (e.g. a acPostProcForPut would act upon the temporary filename). -# # Valid values for this option are 'Yes' and 'No'. +# # Valid values for this option are 'On'/'Yes' and 'Off'/'No'. # # -# #DavRodsTmpfileRollback No +# #DavRodsTmpfileRollback Off # # # When using the davrods-locallock DAV provider (see the 'Dav' # # directive above), this option can be used to set the location of the @@ -136,7 +171,7 @@ # # # # To avoid cleartext password communication we strongly recommend to -# # enable davrods only over SSL. +# # enable Davrods only over SSL. # # For HTTPS-only access, change the port at the start of the vhost block # # from 80 to 443 and add your SSL options below. # diff --git a/package/changelog.txt b/package/changelog.txt index f319eea..a822513 100644 --- a/package/changelog.txt +++ b/package/changelog.txt @@ -1,3 +1,6 @@ +* Mon Aug 7 2017 Chris Smeele - 4.2.1_1.2.0-1 +- Added an anonymous access mode + * Tue Jul 19 2017 Chris Smeele - 4.2.1_1.1.1-1 - Changed build system to CMake - Now supports iRODS 4.2.1 client libraries diff --git a/repo.c b/repo.c index 89a678c..d7195fc 100644 --- a/repo.c +++ b/repo.c @@ -20,6 +20,7 @@ * along with Davrods. If not, see . */ #include "repo.h" +#include "auth.h" // For anonymous access. #include #include @@ -56,6 +57,71 @@ static const char *get_basename(const char *path) { return path; } +/** + * \brief Obtain the fully inited Davrods memory pool. + * + * If Davrods is running with HTTP Basic auth enabled, then the pool + * and the iRODS connection are set up by auth.c before we ever enter + * repo.c. We can then simply return the pool from the request. + * + * Otherwise, if Basic auth is disabled, then the first time this + * function is entered in a HTTP connection, the pool and iRODS + * connection do not yet exist. If in that case AnonymousMode is + * turned on, we will set up the pool and authenticate to iRODS as the + * configured anonymous user. + * + * It is a configuration error if neither basic auth nor anonymous + * mode is enabled. + * + * \param[in] r an apache request record. + * \param[out] pool the fully inited davrods memory pool. + * + * \return NULL if succesful, otherwise a dav error. + */ +static dav_error *get_davrods_pool(request_rec *r, apr_pool_t **pool) { + + *pool = NULL; + int status = apr_pool_userdata_get((void**)pool, "davrods_pool", r->connection->pool); + if (status == 0 && *pool) { + // OK! + return NULL; + + } else { + // Not authenticated yet. + davrods_dir_conf_t *conf = ap_get_module_config( + r->per_dir_config, + &davrods_module + ); + assert(conf); + + if (conf->anonymous_mode == DAVRODS_ANONYMOUS_MODE_ON) { + + authn_status result = check_rods(r, conf->anonymous_auth_username, conf->anonymous_auth_password); + + if (result == AUTH_GRANTED) { + int status = apr_pool_userdata_get((void**)pool, "davrods_pool", r->connection->pool); + assert(status == 0 && *pool); // Logic error - pool must have been set by auth module. + return NULL; + } else { + // 401 and 403 are not appropriate for this error - it + // is a configuration issue, not something that can + // be resolved by the user. + return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0, + "Anonymous mode is enabled but Davrods couldn't log in " + "with the configured anonymous credentials (option DavRodsAnonymousLogin) " + "and the configured auth scheme (option DavRodsAuthScheme)."); + } + } else { + // No basic auth and no anonymous mode. What do you expect us to do? + return dav_new_error(r->pool, HTTP_INTERNAL_SERVER_ERROR, 0, 0, + "iRODS connection could not be set up due to a configuration error: " + "Either enable anonymous access mode (DavRodsAnonymousMode On) " + "or enable Davrods' basic auth provider (Require valid-user, AuthType Basic, AuthBasicProvider irods)."); + } + } +} + +// Used by the dav_repo_walk function for e.g. recursive copy and move. struct dav_repo_walker_private { const dav_walk_params *params; dav_walk_resource wres; @@ -63,6 +129,7 @@ struct dav_repo_walker_private { dav_resource resource; }; +// Used for file uploads to iRODS. struct dav_stream { apr_pool_t *pool; @@ -142,7 +209,7 @@ static dav_error *set_rods_path_from_uri(dav_resource *resource) { * \param[out] dest * \param[in] src * - * \return + * \return */ static void copy_resource_context(dav_resource_private *dest, const dav_resource_private *src) { *dest = *src; @@ -173,7 +240,7 @@ static const char *get_rods_root(apr_pool_t *davrods_pool, request_rec *r) { } else if (conf->rods_exposed_root_type == DAVRODS_ROOT_USER_DIR) { const char *username = NULL; int status = apr_pool_userdata_get((void**)&username, "username", davrods_pool); - assert(status == 0); + assert(status == 0 && username); root = apr_pstrcat(davrods_pool, "/", conf->rods_zone, "/home/", username, @@ -272,7 +339,7 @@ static dav_error *get_dav_resource_rods_info(dav_resource *resource) { * \param use_checked_in unused * \param[out] result_resource * - * \return + * \return */ static dav_error *dav_repo_get_resource( request_rec *r, @@ -297,14 +364,18 @@ static dav_error *dav_repo_get_resource( ); assert(res_private->conf); + // Get Davrods memory pool and make sure the user is logged in. + dav_error *err = get_davrods_pool(r, &res_private->davrods_pool); + if (err) + return err; + // Obtain iRODS connection. - res_private->davrods_pool = get_davrods_pool_from_req(r); int status = apr_pool_userdata_get((void**)&res_private->rods_conn, "rods_conn", res_private->davrods_pool); - assert(status == 0); + assert(status == 0 && res_private->rods_conn); // Obtain iRODS environment. status = apr_pool_userdata_get((void**)&res_private->rods_env, "env", res_private->davrods_pool); - assert(status == 0); + assert(status == 0 && res_private->rods_env); // Get iRODS exposed root dir. res_private->rods_root = get_rods_root(res_private->davrods_pool, r); @@ -324,7 +395,7 @@ static dav_error *dav_repo_get_resource( resource->pool = res_private->r->pool; resource->info = res_private; - dav_error *err = get_dav_resource_rods_info(resource); + err = get_dav_resource_rods_info(resource); if (err) return err; @@ -442,7 +513,7 @@ static dav_error *dav_repo_open_stream( mode == DAV_MODE_WRITE_SEEKABLE || ( mode == DAV_MODE_WRITE_TRUNC - && resource->info->conf->tmpfile_rollback == DAVRODS_TMPFILE_ROLLBACK_NO + && resource->info->conf->tmpfile_rollback == DAVRODS_TMPFILE_ROLLBACK_OFF ) ) { // Either way, do not use tmpfiles for rollback support. @@ -1448,7 +1519,7 @@ static dav_error *walker( if (ctx->params->lockdb->hooks == davrods_dav_provider_locallock.locks) { WHISPER("Checking locks for <%s>", ctx->resource.uri); - + davrods_locklocal_lock_list_t *locked_name; dav_error *err = davrods_locklocal_get_locked_entries( db, @@ -1490,7 +1561,7 @@ static dav_error *walker( ctx->resource.info->rods_path[rods_path_len] = '/'; strcpy(ctx->resource.info->rods_path + rods_path_len + 1, name); } - + ctx->resource.exists = 0; ctx->resource.collection = 0; @@ -1508,7 +1579,7 @@ static dav_error *walker( } -#else +#else // Can we support other locking providers' LOCKNULL walking // functionality? (there are no other locking providers as far // as I know).