admserv/cgi-src40/start_config_ds.c | 11 ++
mod_admserv/mod_admserv.c | 150 ++++++++++++++++++++++++------------
2 files changed, 114 insertions(+), 47 deletions(-)
New commits:
commit 571f3be443fd31b14891412225b417e896457ba2
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Thu Oct 10 15:49:34 2013 -0600
Ticket #222 Admin Express issues "Internal Server Error" when the Config DS
is down.
https://fedorahosted.org/389/ticket/222
Reviewed by: nhosoi (Thanks!)
Branch: master
Fix Description: When the config ds is down, show a page to the user with a
button to start the config ds. If the user presses the button, the config
ds is started, and the user is redirected back to the admin server home
page.
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
diff --git a/admserv/cgi-src40/start_config_ds.c b/admserv/cgi-src40/start_config_ds.c
index 299db1c..de29887 100644
--- a/admserv/cgi-src40/start_config_ds.c
+++ b/admserv/cgi-src40/start_config_ds.c
@@ -62,11 +62,16 @@ success_exit()
int
main(int argc, char *argv[])
{
+ int _ai = ADMUTIL_Init();
int ret_val = 0;
char *startcmd = 0;
AdmldapInfo info;
+ char *method = NULL;
+ char *redir = NULL;
char *configdir = util_get_conf_dir();
+ (void)_ai; /* get rid of unused variable warning */
+ method = getenv("REQUEST_METHOD");
/* find and open the AS config file adm.conf */
info = admldapBuildInfoOnly(configdir, &ret_val);
@@ -82,6 +87,12 @@ main(int argc, char *argv[])
if (ret_val != 0)
return error_exit("Execution of the StartConfigDS command returned
non-zero");
+ if (method && !strcmp(method, "POST") &&
!post_begin(stdin) &&
+ (redir = get_cgi_var("redir_to", NULL, NULL))) {
+ printf("Content-Type: text/html\nLocation: %s\n\n", redir);
+ exit(0);
+ }
+
return success_exit();
}
diff --git a/mod_admserv/mod_admserv.c b/mod_admserv/mod_admserv.c
index eacf1e8..d6d2e19 100644
--- a/mod_admserv/mod_admserv.c
+++ b/mod_admserv/mod_admserv.c
@@ -110,6 +110,7 @@
#define RQ_NOTES_SIEPWD "siepwd"
#define RQ_NOTES_COMMAND_NAME "command-name"
#define RQ_NOTES_AUTHZ_REQUIRED "authz-required"
+#define RQ_NOTES_CONFIGDSDOWN "configdsdown"
#define RUNTIME_COMMAND_BASE (char*)"commands/"
#define AUTH_URI "/admin-serv/authenticate"
#define MOD_ADMSERV_CONFIG_KEY "mod_admserv"
@@ -682,7 +683,7 @@ admserv_ldap_auth_userdn_password(LDAP *server,
if (ldapError) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0 /* status */, NULL,
"Could not bind as [%s]: ldap error %d: %s",
- userdn, ldapError, ldap_err2string(ldapError));
+ userdn ? userdn : "(anon)", ldapError,
ldap_err2string(ldapError));
return ldapError;
}
@@ -693,7 +694,7 @@ admserv_ldap_auth_userdn_password(LDAP *server,
*pw_expiring = 0;
ap_log_error(APLOG_MARK, APLOG_WARNING, 0 /* status */, NULL,
"The password for user DN [%s] has expired - please
reset it",
- userdn);
+ userdn ? userdn : "(anon)");
}
else if(!(strcmp(ctrls[i]->ldctl_oid, LDAP_CONTROL_PWEXPIRING))) {
/* "The password is expiring in n seconds" */
@@ -702,7 +703,7 @@ admserv_ldap_auth_userdn_password(LDAP *server,
*pw_expiring = atoi(ctrls[i]->ldctl_value.bv_val);
ap_log_error(APLOG_MARK, APLOG_WARNING, 0 /* status */, NULL,
"The password for user DN [%s] will expire in %d
seconds",
- userdn, *pw_expiring);
+ userdn ? userdn : "(anon)", *pw_expiring);
}
}
}
@@ -847,6 +848,8 @@ buildUGInfo(char** errorInfo, const request_rec *r) {
"buildUGInfo(): unable to initialize TLS connection to LDAP
host %s port %d: %d",
host, admldapGetPort(info), error);
PL_strfree(host);
+ apr_table_set(r->notes, RQ_NOTES_CONFIGDSDOWN, apr_pstrdup(module_pool,
"1"));
+
goto done;
}
@@ -1039,11 +1042,11 @@ admserv_error_std(request_rec *r, char *reason)
}
static int
-check_auth_tasks_cache(char *dn, const char *userdn, request_rec *r, long now, int
send_response)
+check_auth_tasks_cache(char *dn, const char *userdn, request_rec *r, long now, int
send_response, char **retmsg)
{
TaskCacheEntry *cache_entry;
char normEntryDN[1024];
- long createTime;
+ long createTime = 0;
char *msg;
adm_normalize_dn(dn, normEntryDN);
@@ -1055,7 +1058,7 @@ check_auth_tasks_cache(char *dn, const char *userdn, request_rec *r,
long now, i
normEntryDN);
goto bad;
}
- if (!(createTime = (long)HashTableFind(cache_entry->auth_userDNs, userdn))) {
+ if (userdn && !(createTime =
(long)HashTableFind(cache_entry->auth_userDNs, userdn))) {
msg = apr_psprintf(r->pool,
"check_auth_tasks_cache: found task [%s] but user [%s] is
not authorized",
dn, userdn);
@@ -1064,7 +1067,7 @@ check_auth_tasks_cache(char *dn, const char *userdn, request_rec *r,
long now, i
if ((now - createTime) > cacheLifetime) {
msg = apr_psprintf(r->pool, "check_auth_tasks_cache: task [%s] user [%s]
entry has expired %ld",
- dn, userdn, (now - createTime));
+ dn, userdn ? userdn : "(anon)", (now -
createTime));
goto bad;
}
@@ -1079,6 +1082,8 @@ bad:
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r, "%s", msg);
if (send_response) {
return admserv_error_std(r, msg);
+ } else if (retmsg) {
+ *retmsg = msg;
}
return DONE;
@@ -1119,7 +1124,7 @@ sync_task_sie_data(const char *name, char *query, void *arg,
request_rec *r)
replace the siedn with the userdn - fortunately it doesn't use the
siedn as the SIE DN */
admldapSetSIEDN(ldapInfo, userdn);
- if (NULL == passwd) { /* use the passwd in cache if possible */
+ if (userdn && (NULL == passwd)) { /* use the passwd in cache if possible */
cache_entry = (UserCacheEntry*)HashTableFind(auth_users, userdn);
if (cache_entry) {
passwd = cache_entry->userPW;
@@ -1276,14 +1281,14 @@ task_update_registry_server_bindpw(char *uid, char *password,
/* authenticate failed: Should not continue */
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
"task_update_registry_server_bindpw(): failed to authenticate as %s:
%s",
- userDN, ldap_err2string(ldapError));
+ userDN ? userDN : "(anon)", ldap_err2string(ldapError));
goto bailout;
case LDAP_NO_SUCH_OBJECT:
case LDAP_ALIAS_PROBLEM:
case LDAP_INVALID_DN_SYNTAX:
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
"task_update_registry_server_bindpw(): bad userdn %s: %s",
- userDN, ldap_err2string(ldapError));
+ userDN ? userDN : "(anon)", ldap_err2string(ldapError));
goto bailout;
default:
ap_log_error(APLOG_MARK, APLOG_ERR, 0, NULL,
@@ -1314,7 +1319,7 @@ task_update_registry_server_bindpw(char *uid, char *password,
create_auth_users_cache_entry(uid, adminDN, password, ldapURL);
/* We only want to reset the pwd in the request if RQ_NOTES_USERDN is the admin user
*/
- if(strcasecmp(adminDN, userDN) == 0) {
+ if(userDN && (strcasecmp(adminDN, userDN) == 0)) {
apr_table_set(r->notes, RQ_NOTES_USERPW, password);
}
@@ -1502,6 +1507,7 @@ populate_tasks_from_server(char *serverid, const void *sieDN, void
*userdata)
char *execRefArgs = NULL;
struct berval **vals, **vals2;
TaskCacheEntry *cache_entry;
+ char *userdn;
dn = ldap_get_dn(server, e);
@@ -1542,15 +1548,18 @@ populate_tasks_from_server(char *serverid, const void *sieDN,
void *userdata)
}
cache_entry->execRefArgs = execRefArgs ? apr_pstrdup(module_pool, execRefArgs)
: NULL;
cache_entry->logSuppress = (vals2 && vals[0] &&
!strncasecmp(vals2[0]->bv_val, LOG_SUPPRESS_ON_VALUE, vals2[0]->bv_len));
- HashTableInsert(cache_entry->auth_userDNs, apr_pstrdup(module_pool,
data->userDN),
- (char*)(data->now));
-
+ if (data->userDN) {
+ userdn = apr_pstrdup(module_pool, data->userDN);
+ } else {
+ userdn = apr_pstrdup(module_pool, "");
+ }
+ HashTableInsert(cache_entry->auth_userDNs, userdn, (char*)(data->now));
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL,
"populate_tasks_from_server(): Added task entry [%s:%s:%s] for
user [%s]",
normDN, cache_entry->execRef,
cache_entry->execRefArgs ? cache_entry->execRefArgs :
"",
- data->userDN);
+ userdn);
ldap_value_free_len(vals);
if (vals2)
@@ -1575,22 +1584,29 @@ populate_task_cache_entries(const char *userDN, LDAP *server)
HashTableEnumerate(servers, populate_tasks_from_server, &data);
}
+#define STARTDS_IDENTIFIER "tasks/operation/StartConfigDS"
+#define STARTDS_CGI "start_config_ds"
+#define IS_START_CONFIG_DS_REQ(uri, serverid, userdn, user) \
+ uri && !STRNCASECMP(uri, STARTDS_IDENTIFIER, strlen(STARTDS_IDENTIFIER))
&& \
+ serverid && !STRCMP(serverid, "admin-serv") && /* is local
superuser */ !userdn && user
+
static int
admserv_check_authz(request_rec *r)
{
int ldapError;
char entryDN[LINE_LENGTH];
char *p;
- char *siedn; /* this is looked up from the serverid, which is
+ char *siedn = NULL; /* this is looked up from the serverid, which is
extracted from the uri */
- LDAP *server;
- const char *userdn;
- const char *pw;
- char *serverid;
+ LDAP *server = NULL;
+ const char *userdn = NULL;
+ const char *pw = NULL;
+ char *serverid = NULL;
char *storage = entryDN;
- char *uri;
- char *saveduri;
+ char *uri = NULL;
+ char *saveduri = NULL;
long now;
+ int is_start_config_ds_req = 0;
int tries = 0;
admserv_config *cf = ap_get_module_config(r->per_dir_config,
&admserv_module);
@@ -1621,6 +1637,12 @@ admserv_check_authz(request_rec *r)
saveduri = apr_pstrdup(r->pool, uri);
*p = '\0';
+ userdn = apr_table_get(r->notes, RQ_NOTES_USERDN);
+ pw = apr_table_get(r->notes, RQ_NOTES_USERPW);
+
+ if (IS_START_CONFIG_DS_REQ(uri, serverid, userdn, r->user)) {
+ is_start_config_ds_req = 1;
+ }
if (!(siedn = (char*)HashTableFind(servers, serverid))) {
/* DT 4/6/98 -- If we're seeing a serverid for the first time, then we try to
do
* a resync to pull in new data for the serverid. If it still
fails,
@@ -1629,10 +1651,12 @@ admserv_check_authz(request_rec *r)
admserv_runtime_command_exec(RUNTIME_RESYNC_COMMAND, r->args, r);
if (!(siedn = (char*)HashTableFind(servers, serverid))) {
- ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
- "admserv_check_authz(): unable to find registered server
(%s)",
- serverid);
- return admserv_error(r, HTTP_BAD_REQUEST, "server not registered");
/*i18n*/
+ if (!is_start_config_ds_req) {
+ ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
+ "admserv_check_authz(): unable to find registered
server (%s)",
+ serverid);
+ return admserv_error(r, HTTP_BAD_REQUEST, "server not
registered"); /*i18n*/
+ }
}
}
@@ -1644,7 +1668,8 @@ admserv_check_authz(request_rec *r)
return OK;
}
- if (!build_full_DN(&storage, entryDN+LINE_LENGTH, uri, siedn)) {
+ entryDN[0] = '\0';
+ if (siedn && (!build_full_DN(&storage, entryDN+LINE_LENGTH, uri, siedn)))
{
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"admserv_check_authz(): unable to build DN from URL - bad URL
[%s]",
uri);
@@ -1653,20 +1678,26 @@ admserv_check_authz(request_rec *r)
convert_to_lower_case(entryDN);
- userdn = apr_table_get(r->notes, RQ_NOTES_USERDN);
- pw = apr_table_get(r->notes, RQ_NOTES_USERPW);
-
/*
* if we got here, we either have a userdn - user was authenticated via LDAP
* or r->user is set and was therefore authenticated via mod_auth - if both
* LDAP and mod_auth auth fail, we should not be here - not an authenticated user
*/
if (!userdn && r->user) {
- int retval = check_auth_tasks_cache(entryDN, LOCAL_SUPER_NAME, r, 0, 1 /*
send_response */);
+ const char *configdsdown = apr_table_get(r->notes, RQ_NOTES_CONFIGDSDOWN);
+ int send_response = configdsdown ? 0 : 1; /* do not send response if configds is
down - let handler */
+ char *retmsg = NULL;
+ int retval = check_auth_tasks_cache(entryDN, LOCAL_SUPER_NAME, r, 0,
send_response, &retmsg);
if (retval != OK) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"admserv_check_authz: task [%s] not cached for local
superuser",
entryDN);
+ if (configdsdown) {
+ return OK; /* let the admserv_config_ds_down handler handle this
situation */
+ }
+ if (!send_response) {
+ return admserv_error_std(r, retmsg);
+ }
return retval;
}
goto found;
@@ -1684,7 +1715,7 @@ admserv_check_authz(request_rec *r)
now = time(0);
- if (check_auth_tasks_cache(entryDN, userdn, r, now, 0 /* no response */) == OK) {
+ if (check_auth_tasks_cache(entryDN, userdn, r, now, 0 /* no response */, NULL) == OK)
{
goto found;
}
@@ -1711,7 +1742,7 @@ admserv_check_authz(request_rec *r)
if(!(server = openLDAPConnection(®istryServer))) {
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"admserv_check_authz(): unable to LDAP BIND as [%s] to
%s:%d",
- userdn, registryServer.host, registryServer.port);
+ userdn ? userdn : "(anon)", registryServer.host,
registryServer.port);
return admserv_error_std(r, "unable to open LDAPConnection");
/*i18n*/
}
} while (server != NULL && ++tries < 2);
@@ -1720,11 +1751,11 @@ admserv_check_authz(request_rec *r)
closeLDAPConnection(server);
if ((ldapError == LDAP_CONNECT_ERROR) || (ldapError == LDAP_SERVER_DOWN)) {
- int retval = check_auth_tasks_cache(entryDN, userdn, r, 0, 1 /* send response
*/); /* Try the cache, ignoring expiration */
+ int retval = check_auth_tasks_cache(entryDN, userdn, r, 0, 1 /* send response
*/, NULL); /* Try the cache, ignoring expiration */
if (retval != OK) {
ap_log_rerror(APLOG_MARK, APLOG_DEBUG, 0, r,
"admserv_check_authz: could not find cached task [%s]
for [%s]",
- entryDN, userdn);
+ entryDN, userdn ? userdn : "(anon)");
return retval;
}
goto found;
@@ -1732,7 +1763,7 @@ admserv_check_authz(request_rec *r)
ap_log_rerror(APLOG_MARK, APLOG_ERR, 0, r,
"admserv_check_authz(): got LDAP error %d talking to %s:%d -
possible user [%s] not authorized",
- ldapError, registryServer.host, registryServer.port, userdn);
+ ldapError, registryServer.host, registryServer.port, userdn ?
userdn : "(anon)");
return admserv_error(r, HTTP_UNAUTHORIZED, "invalid user credentials");
/*i18n*/
}
@@ -1742,14 +1773,14 @@ admserv_check_authz(request_rec *r)
populate_task_cache_entries(userdn, server);
closeLDAPConnection(server);
- if (check_auth_tasks_cache(entryDN, userdn, r, now, 0 /* no response */) == OK) {
+ if (check_auth_tasks_cache(entryDN, userdn, r, now, 0 /* no response */, NULL) == OK)
{
goto found;
}
ap_log_rerror(APLOG_MARK, APLOG_CRIT, 0, r,
"admserv_check_authz(): Task [%s] not found for user [%s] -
either"
" the task was not registered or the user was not
authorized",
- entryDN, userdn);
+ entryDN, userdn ? userdn : "(anon)");
return admserv_error(r, HTTP_UNAUTHORIZED, "task not found or
unauthorized"); /*i18n*/
/* This is remapping - converting the requested URI to the actual CGI filename
@@ -1762,12 +1793,7 @@ found:
* Treat StartConfigDS as a special task. This will be the case if the user was
* authenticated as the local superuser (admpw) and the server-id is
"admin-serv"
*/
-# define STARTDS_IDENTIFIER "tasks/operation/StartConfigDS"
-# define STARTDS_CGI "start_config_ds"
- if (!STRNCASECMP(saveduri, STARTDS_IDENTIFIER, strlen(STARTDS_IDENTIFIER))
&&
- !STRCMP(serverid, "admin-serv") &&
- /* is local superuser */
- !userdn && r->user) {
+ if (is_start_config_ds_req) {
apr_status_t status;
if (!cf->cgibindir) {
@@ -2620,6 +2646,7 @@ static const char * set_version_string(cmd_parms *cmd, void *dconf,
const char *
static int userauth(request_rec *r)
{
char *dummy = NULL;
+ const char *userdn = NULL;
if (strcmp(r->handler, "user-auth"))
return DECLINED;
@@ -2633,12 +2660,15 @@ static int userauth(request_rec *r)
buildUGInfo(&dummy, r);
}
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "userauth, bind %s",
- apr_table_get(r->notes, RQ_NOTES_USERDN));
+ userdn = apr_table_get(r->notes, RQ_NOTES_USERDN);
+ if (!userdn) {
+ userdn = "(anon)";
+ }
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, NULL, "userauth, bind %s",
userdn);
ap_set_content_type(r, "text/html");
- ap_rprintf(r, "UserDN: %s\n", apr_table_get(r->notes,
RQ_NOTES_USERDN));
+ ap_rprintf(r, "UserDN: %s\n", userdn);
ap_rprintf(r, "UserDirectory: ldap%s://%s:%d/%s\n",
userGroupServer.secure ? "s" : "",
userGroupServer.host, userGroupServer.port,
@@ -2847,6 +2877,31 @@ admserv_command_handler(request_rec *r)
return DONE;
}
+static void
+show_start_config_ds_page(request_rec *r)
+{
+ ap_set_content_type(r, "text/html");
+ ap_rputs(DOCTYPE_HTML_3_2, r);
+ ap_rputs("<HTML><HEAD><TITLE>Configuration Directory Server is
down</TITLE></HEAD>", r);
+ ap_rputs("<BODY>", r);
+ ap_rputs("<FORM name=\"startconfigds\" method=\"POST\"
action=\"/admin-serv/tasks/operation/StartConfigDS\">", r);
+ ap_rprintf(r, "<INPUT type=\"hidden\" name=\"redir_to\"
value=\"%s\">", "/dist/download");
+ ap_rputs("The Configuration Directory Server is down. To restart, click here:
", r);
+ ap_rputs("<INPUT type=\"submit\" name=\"startbutton\"
value=\"Start Config DS\">", r);
+ ap_rputs("</FORM></BODY></HTML>", r);
+}
+
+static int
+admserv_config_ds_down(request_rec *r)
+{
+ if (apr_table_get(r->notes, RQ_NOTES_CONFIGDSDOWN)) {
+ show_start_config_ds_page(r);
+ return DONE;
+ }
+
+ return DECLINED;
+}
+
static int fixup_adminsdk(request_rec *r)
{
admserv_config *cf = ap_get_module_config(r->per_dir_config,
@@ -2994,6 +3049,7 @@ static void register_hooks(apr_pool_t *p)
ap_hook_fixups(fixup_admin_server_header, NULL, NULL, APR_HOOK_MIDDLE);
/* do per forked child init */
ap_hook_child_init(admserv_init_child, NULL,NULL, APR_HOOK_MIDDLE);
+ ap_hook_handler(admserv_config_ds_down, NULL, NULL, APR_HOOK_LAST);
}
static const command_rec mod_adm_cmds[] =