ldap/servers
by Richard Allen Megginson
ldap/servers/slapd/daemon.c | 111 ++++++++++++++++++++++++--------------------
1 file changed, 62 insertions(+), 49 deletions(-)
New commits:
commit 24b751cc724468a7bce5f86848a82e4b03e24a3c
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Fri May 10 15:11:13 2013 -0600
Ticket #47359 - new ldap connections can block ldaps and ldapi connections
https://fedorahosted.org/389/ticket/47359
Reviewed by: lkrispen
Branch: master
Fix Description: description
In the polling thread, first process all of the new connection requests from
the listening sockets, then process any new operation read requests
The listener_idxs keeps track of the index of the active listeners in the
poll fd array, and keeps a pointer to the listenfd object for that
listener. This allows us to very quickly scan through the poll fd array
and find the ready listeners. The work of scanning through the array
and handling the new connection requests has been moved to a new function
handle_listeners().
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
(cherry picked from commit 115ab1d9a3f026e8523b91bf62245a25454a3e8a)
diff --git a/ldap/servers/slapd/daemon.c b/ldap/servers/slapd/daemon.c
index 3121e01..b4bbc7f 100644
--- a/ldap/servers/slapd/daemon.c
+++ b/ldap/servers/slapd/daemon.c
@@ -138,6 +138,15 @@ void disk_monitoring_stop();
#define FDS_SIGNAL_PIPE 0
+typedef struct listener_info {
+ int idx; /* index of this listener in the ct->fd array */
+ PRFileDesc *listenpr; /* the listener fd */
+ int secure;
+ int local;
+} listener_info;
+
+#define SLAPD_POLL_LISTEN_READY(xxflagsxx) (xxflagsxx & PR_POLL_READ)
+
static int get_configured_connection_table_size();
#ifdef RESOLVER_NEEDS_LOW_FILE_DESCRIPTORS
static void get_loopback_by_addr( void );
@@ -151,7 +160,7 @@ static PRFileDesc **createprlistensockets(unsigned short port,
static const char *netaddr2string(const PRNetAddr *addr, char *addrbuf,
size_t addrbuflen);
static void set_shutdown (int);
-static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read);
+static void setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners);
#ifdef HPUX10
static void* catch_signals();
@@ -917,6 +926,30 @@ disk_monitoring_thread(void *nothing)
}
}
+static void
+handle_listeners(Connection_Table *ct, listener_info *listener_idxs, int n_listeners)
+{
+ int idx;
+ for (idx = 0; idx < n_listeners; ++idx) {
+ int fdidx = listener_idxs[idx].idx;
+ PRFileDesc *listenfd = listener_idxs[idx].listenfd;
+ int secure = listener_idxs[idx].secure;
+ int local = listener_idxs[idx].local;
+ if (fdidx && listenfd) {
+ if (SLAPD_POLL_LISTEN_READY(ct->fd[fdidx].out_flags)) {
+ /* accept() the new connection, put it on the active list for handle_pr_read_ready */
+ int rc = handle_new_connection(ct, SLAPD_INVALID_SOCKET, listenfd, secure, local);
+ if (rc) {
+ LDAPDebug1Arg(LDAP_DEBUG_CONNS, "Error accepting new connection listenfd=%d\n",
+ PR_FileDesc2NativeHandle(listenc->c_prfd));
+ continue;
+ }
+ }
+ }
+ }
+ return;
+}
+
void slapd_daemon( daemon_ports_t *ports )
{
/* We are passed some ports---one for regular connections, one
@@ -944,6 +977,8 @@ void slapd_daemon( daemon_ports_t *ports )
PRThread *time_thread_p;
int threads;
int in_referral_mode = config_check_referral_mode();
+ int n_listeners = 0; /* number of listener sockets */
+ listener_info *listener_idxs = NULL; /* array of indexes of listener sockets in the ct->fd array */
int connection_table_size = get_configured_connection_table_size();
the_connection_table= connection_table_new(connection_table_size);
@@ -1058,6 +1093,7 @@ void slapd_daemon( daemon_ports_t *ports )
netaddr2string(&ports->n_listenaddr, addrbuf, sizeof(addrbuf)),
ports->n_port, oserr, slapd_system_strerror( oserr ) );
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
+ n_listeners++;
}
#else
if ( n_tcps != NULL ) {
@@ -1075,6 +1111,7 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
#endif
@@ -1094,6 +1131,7 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
@@ -1112,11 +1150,13 @@ void slapd_daemon( daemon_ports_t *ports )
slapd_pr_strerror( prerr ));
g_set_shutdown( SLAPI_SHUTDOWN_EXIT );
}
+ n_listeners++;
}
}
#endif /* ENABLE_LDAPI */
#endif
+ listener_idxs = (listener_info *)slapi_ch_calloc(n_listeners, sizeof(*listener_idxs));
/* Now we write the pid file, indicating that the server is finally and listening for connections */
write_pid_file();
@@ -1143,7 +1183,7 @@ void slapd_daemon( daemon_ports_t *ports )
/* This select needs to timeout to give the server a chance to test for shutdown */
select_return = select(connection_table_size, &readfds, NULL, 0, &wakeup_timer);
#else
- setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll);
+ setup_pr_read_pds(the_connection_table,n_tcps,s_tcps,i_unix,&num_poll,listener_idxs,n_listeners);
select_return = POLL_FN(the_connection_table->fd, num_poll, pr_timeout);
#endif
switch (select_return) {
@@ -1179,52 +1219,8 @@ void slapd_daemon( daemon_ports_t *ports )
handle_read_ready(the_connection_table,&readfds);
clear_signal(&readfds);
#else
- tcps = NULL;
- /* info for n_tcps is always in fd[n_tcps ~ n_tcpe] */
- if( NULL != n_tcps ) {
- for (i = the_connection_table->n_tcps;
- i < the_connection_table->n_tcpe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = n_tcps[i - the_connection_table->n_tcps]; */
- tcps = the_connection_table->fd[i].fd;
- break;
- }
- }
- }
- /* info for s_tcps is always in fd[s_tcps ~ s_tcpe] */
- if ( NULL == tcps && NULL != s_tcps ) {
- for (i = the_connection_table->s_tcps;
- i < the_connection_table->s_tcpe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = s_tcps[i - the_connection_table->s_tcps]; */
- tcps = the_connection_table->fd[i].fd;
- secure = 1;
- break;
- }
- }
- }
-#if defined(ENABLE_LDAPI)
- /* info for i_unix is always in fd[i_unixs ~ i_unixe] */
- if ( NULL == tcps && NULL != i_unix ) {
- for (i = the_connection_table->i_unixs;
- i < the_connection_table->i_unixe; i++) {
- if (the_connection_table->fd[i].out_flags &
- SLAPD_POLL_FLAGS ) {
- /* tcps = i_unix[i - the_connection_table->i_unixs]; */
- tcps = the_connection_table->fd[i].fd;
- local = 1;
- break;
- }
- }
- }
-#endif /* ENABLE_LDAPI */
-
- /* If so, then handle a new connection */
- if ( tcps != NULL ) {
- handle_new_connection(the_connection_table,SLAPD_INVALID_SOCKET,tcps,secure,local);
- }
+ /* handle new connections from the listeners */
+ handle_listeners(the_connection_table, listener_idxs, n_listeners);
/* handle new data ready */
handle_pr_read_ready(the_connection_table, connection_table_size);
clear_signal(the_connection_table->fd);
@@ -1545,7 +1541,7 @@ static void setup_read_fds(Connection_Table *ct, fd_set *readfds, int n_tcps, in
static int first_time_setup_pr_read_pds = 1;
static int listen_addr_count = 0;
static void
-setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read)
+setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps, PRFileDesc **i_unix, PRIntn *num_to_read, listener_info *listener_idxs, int max_listeners)
{
Connection *c= NULL;
Connection *next= NULL;
@@ -1555,6 +1551,7 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
PRIntn count = 0;
slapdFrontendConfig_t *slapdFrontendConfig = getFrontendConfig();
int max_threads_per_conn = config_get_maxthreadsperconn();
+ int n_listeners = 0;
accept_new_connections = ((ct->size - g_get_current_conn_count())
> slapdFrontendConfig->reservedescriptors);
@@ -1606,6 +1603,9 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for connections on %d\n", socketdesc, 0, 0 );
}
@@ -1624,6 +1624,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ listener_idxs[n_listeners].secure = 1;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for SSL connections on %d\n", socketdesc, 0, 0 );
}
@@ -1645,6 +1649,10 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
ct->fd[count].fd = *fdesc;
ct->fd[count].in_flags = SLAPD_POLL_FLAGS;
ct->fd[count].out_flags = 0;
+ listener_idxs[n_listeners].listenfd = *fdesc;
+ listener_idxs[n_listeners].idx = count;
+ listener_idxs[n_listeners].local = 1;
+ n_listeners++;
LDAPDebug( LDAP_DEBUG_HOUSE,
"listening for LDAPI connections on %d\n", socketdesc, 0, 0 );
}
@@ -1658,6 +1666,11 @@ setup_pr_read_pds(Connection_Table *ct, PRFileDesc **n_tcps, PRFileDesc **s_tcps
first_time_setup_pr_read_pds = 0;
listen_addr_count = count;
+
+ if (n_listeners < max_listeners) {
+ listener_idxs[n_listeners].idx = 0;
+ listener_idxs[n_listeners].listenfd = NULL;
+ }
}
/* count is the number of entries we've place in the fds array.
10 years, 11 months
ldap/servers
by Mark Reynolds
ldap/servers/plugins/uiduniq/7bit.c | 30 ++++++++++++++++++++++--------
1 file changed, 22 insertions(+), 8 deletions(-)
New commits:
commit bce5557406be22ec69eb38e7fd3230efe6143283
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon May 20 15:09:00 2013 -0400
Ticket 47340 - Deleting a separator ',' in 7-bit check plugin arguments makes the
server fail to start with segfault
Bug Description: If invalid or missing plugin arguments are present in the config entry,
the server will crash at startup. This is because we were not fully
validating all argument values.
Fix Description: Generate an appropriate error at startup when invalid settings are
detected, and gracefully exit.
https://fedorahosted.org/389/ticket/47340
Reviewed by: Noriko(Thanks!!)
diff --git a/ldap/servers/plugins/uiduniq/7bit.c b/ldap/servers/plugins/uiduniq/7bit.c
index fbcc530..ca9792b 100644
--- a/ldap/servers/plugins/uiduniq/7bit.c
+++ b/ldap/servers/plugins/uiduniq/7bit.c
@@ -699,6 +699,7 @@ NS7bitAttr_Init(Slapi_PBlock *pb)
int premdn = SLAPI_PLUGIN_PRE_MODRDN_FN;
BEGIN
+ int attr_count = 0;
int argc;
char **argv;
@@ -731,12 +732,12 @@ NS7bitAttr_Init(Slapi_PBlock *pb)
* Arguments before "," are the 7-bit attribute names. Arguments after
* "," are the subtree DN's.
*/
- if (argc < 1) { err = -1; break; }
- for(;strcmp(*argv, ",") != 0 && argc > 0; argc--, argv++)
- {};
- if (argc == 0) { err = -1; break; }
+ if (argc < 1) { err = -2; break; } /* missing arguments */
+ for(;*argv && strcmp(*argv, ",") != 0 && argc > 0; attr_count++, argc--, argv++);
+ if (argc == 0) { err = -3; break; } /* no comma separator */
+ if(attr_count == 0){ err = -4; break; } /* no attributes */
argv++; argc--;
-
+ if(argc == 0){ err = -5; break; } /* no suffix */
for(;argc > 0;argc--, argv++) {
char *normdn = slapi_create_dn_string_case("%s", *argv);
slapi_ch_free_string(argv);
@@ -761,9 +762,22 @@ NS7bitAttr_Init(Slapi_PBlock *pb)
END
if (err) {
- slapi_log_error(SLAPI_LOG_PLUGIN, "NS7bitAttr_Init",
- "Error: %d\n", err);
- err = -1;
+ if(err == -1){
+ slapi_log_error(SLAPI_LOG_PLUGIN, "NS7bitAttr_Init","Error: %d\n", err);
+ } else if(err == -2){
+ slapi_log_error(SLAPI_LOG_FATAL, "NS7bitAttr_Init",
+ "Invalid plugin arguments - missing arguments\n");
+ } else if(err == -3){
+ slapi_log_error(SLAPI_LOG_FATAL, "NS7bitAttr_Init",
+ "Invalid plugin arguments - missing \",\" separator argument\n");
+ } else if(err == -4){
+ slapi_log_error(SLAPI_LOG_FATAL, "NS7bitAttr_Init",
+ "Invalid plugin arguments - missing attributes\n");
+ } else if(err == -5){
+ slapi_log_error(SLAPI_LOG_FATAL, "NS7bitAttr_Init",
+ "Invalid plugin arguments - missing suffix\n");
+ }
+ err = -1;
}
else
slapi_log_error(SLAPI_LOG_PLUGIN, "NS7bitAttr_Init",
10 years, 11 months
ldap/servers
by Mark Reynolds
ldap/servers/slapd/slapi-plugin.h | 55 +++++++++++++++++++++++++++++++++++++
ldap/servers/slapd/slapi-private.h | 8 -----
2 files changed, 55 insertions(+), 8 deletions(-)
New commits:
commit 10a6b846a05716c1ab11ffcc8f04161e5a8911e0
Author: Mark Reynolds <mreynolds(a)redhat.com>
Date: Mon May 20 12:28:01 2013 -0400
Ticket 283 - Expose slapi_eq_* API
Description: Make the event queue API public.
https://fedorahosted.org/389/ticket/283
Reviewed by: Noriko(Thanks!)
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index 2d618e9..7000df6 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -7419,6 +7419,61 @@ char *slapi_pr_strerror( const PRErrorCode prerrno );
*/
const char *slapi_system_strerror( const int syserrno );
+/* event queue routines and data types */
+
+/**
+ * Represents a scheduled event object.
+ */
+typedef void* Slapi_Eq_Context;
+
+/**
+ * Represents the function that will be performed when an event is triggered.
+ */
+typedef void (*slapi_eq_fn_t)(time_t when, void *arg);
+
+/**
+ * Cause an event to happen exactly once.
+ *
+ * \param fn The function to call when the event is triggered.
+ * \param arg An argument to pass to the called function.
+ * \param when The time that the function should be called.
+ *
+ * \return slapi_eq_context
+ */
+Slapi_Eq_Context slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when);
+
+/**
+ * Cause an event to happen repeatedly.
+ *
+ * \param fn The function to call when the vent is triggered.
+ * \param arg An argument to pass to the called function.
+ * \param when The time that the function should be called.
+ * \param interval The amount of time (in milliseconds) between
+ * successive calls to the function.
+ *
+ * \return slapi_eq_context
+ */
+Slapi_Eq_Context slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval);
+
+/**
+ * Cause a scheduled event to be canceled.
+ *
+ * \param ctx The event object to cancel
+ *
+ * \return 1 If event was found and canceled.
+ * \return 0 If event was not found in the queue.
+ */
+int slapi_eq_cancel(Slapi_Eq_Context ctx);
+
+/**
+ * Return the event's argument.
+ *
+ * \param ctx The event object
+ *
+ * \return A pointer to the event argument.
+ */
+void *slapi_eq_get_arg (Slapi_Eq_Context ctx);
+
#ifdef __cplusplus
}
#endif
diff --git a/ldap/servers/slapd/slapi-private.h b/ldap/servers/slapd/slapi-private.h
index 49ecb52..1e8a53a 100644
--- a/ldap/servers/slapd/slapi-private.h
+++ b/ldap/servers/slapd/slapi-private.h
@@ -1168,14 +1168,6 @@ void addlenstr( lenstr *l, const char *str );
void lenstr_free( lenstr ** );
lenstr *lenstr_new(void);
-/* event queue routines and data types */
-typedef void* Slapi_Eq_Context;
-typedef void (*slapi_eq_fn_t)(time_t when, void *arg);
-Slapi_Eq_Context slapi_eq_once(slapi_eq_fn_t fn, void *arg, time_t when);
-Slapi_Eq_Context slapi_eq_repeat(slapi_eq_fn_t fn, void *arg, time_t when, unsigned long interval);
-int slapi_eq_cancel(Slapi_Eq_Context ctx);
-void *slapi_eq_get_arg (Slapi_Eq_Context ctx);
-
/* config DN */
char *get_config_DN(void);
10 years, 11 months
Branch '389-ds-base-1.3.1' - ldap/servers
by Richard Allen Megginson
ldap/servers/plugins/replication/repl5_inc_protocol.c | 38 ++++++++++++++++++
ldap/servers/plugins/replication/repl5_ruv.c | 32 +++++++++++++++
2 files changed, 70 insertions(+)
New commits:
commit 2909b172a0bc9d8e05298a23df90eca8f9787f8e
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Wed May 15 19:39:24 2013 -0600
Ticket #47362 - ipa upgrade selinuxusermap data not replicating
https://fedorahosted.org/389/ticket/47362
Reviewed by: nhosoi (Thanks!)
Branch: 389-ds-base-1.3.1
Fix Description: When nsslapd-port is set to 0, this causes the
replica purl to be "ldap://hostname:0". At startup, the MMR code looks to
see if this replica purl is in the RUV, by doing a string comparison of this
purl with the ruv replica purl. If it is not there, the MMR code wipes out
this ruv element. Later the code in replica_check_for_data_reload() uses
this RUV to see if it needs to reinit the changelog. Since the RUV doesn't
match the changelog RUV any more, the changelog is erased, which erases
any changes that were made in the meantime. The missing RUV element causes
the supplier to attempt to send over changes which may already exist on the
consumer. If one of these is an ADD, the urp code will correctly flag this
as an attempt to add an entry that already exists, and will turn this into
a replConflict entry. A subsequent attempt to replicate the same ADD will
cause an error in the urp code which will cause it to return err=53.
Replication will then become stuck on this update - it will keep trying to
send it over and over again, and will not be able to proceed.
The only workaround is a replica reinit of the replica, to get the database
RUV and changelog in a consistent state.
I've also added some additional RUV debugging when using the REPL log level.
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
(cherry picked from commit 614ce4e4b1774526bb8c4ad6c43a1582adcc30ec)
(cherry picked from commit 6236d7a7df86141311d731ce737d1c0986d564ee)
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
index 72d2d6c..fa442fe 100644
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -1941,6 +1941,44 @@ repl5_inc_stop(Private_Repl_Protocol *prp)
agmt_get_long_name(prp->agmt),
PR_IntervalToSeconds(now-start));
}
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
+ if (NULL == prp->replica_object) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: protocol replica_object is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ Replica *replica;
+ object_acquire(prp->replica_object);
+ replica = object_get_data(prp->replica_object);
+ if (NULL == replica) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: replica is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ Object *ruv_obj = replica_get_ruv(replica);
+ if (NULL == ruv_obj) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: ruv_obj is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ RUV *ruv;
+ object_acquire(ruv_obj);
+ ruv = (RUV*)object_get_data (ruv_obj);
+ if (NULL == ruv) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: ruv is NULL\n",
+ agmt_get_long_name(prp->agmt));
+
+ } else {
+ ruv_dump(ruv, "Database RUV", NULL);
+ }
+ object_release(ruv_obj);
+ }
+ }
+ object_release(prp->replica_object);
+ }
+
+ }
return return_value;
}
diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c
index 9ce9768..107c4f0 100644
--- a/ldap/servers/plugins/replication/repl5_ruv.c
+++ b/ldap/servers/plugins/replication/repl5_ruv.c
@@ -208,6 +208,9 @@ ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *
Slapi_Value *value;
const struct berval *bval;
const char *purl = NULL;
+ char *localhost = get_localhost_DNS();
+ size_t localhostlen = localhost ? strlen(localhost) : 0;
+ int port = config_get_port();
return_value = RUV_SUCCESS;
@@ -236,16 +239,30 @@ ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *
RUVElement *ruve = get_ruvelement_from_berval(bval);
if (NULL != ruve)
{
+ char *ptr;
/* Is the local purl already in the ruv ? */
if ( (*contain_purl==0) && ruve->replica_purl && purl && (strncmp(ruve->replica_purl, purl, strlen(purl))==0) )
{
*contain_purl = ruve->rid;
}
+ /* ticket 47362 - nsslapd-port: 0 causes replication to break */
+ else if ((*contain_purl==0) && ruve->replica_purl && (port == 0) && localhost &&
+ (ptr = strstr(ruve->replica_purl, localhost)) && (ptr != ruve->replica_purl) &&
+ (*(ptr - 1) == '/') && (*(ptr+localhostlen) == ':'))
+ {
+ /* same hostname, but port number may have been temporarily set to 0
+ * just allow it with whatever port number is already in the replica_purl
+ * do not reset the port number, do not tell the configure_ruv code that there
+ * is anything wrong
+ */
+ *contain_purl = ruve->rid;
+ }
dl_add ((*ruv)->elements, ruve);
}
}
}
}
+ slapi_ch_free_string(&localhost);
}
}
return return_value;
@@ -1291,6 +1308,11 @@ ruv_compare_ruv(const RUV *ruv1, const char *ruv1name, const RUV *ruv2, const ch
const char *ruvbnames[] = {ruv2name, ruv1name};
const int nitems = 2;
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
+ ruv_dump(ruv1, (char *)ruv1name, NULL);
+ ruv_dump(ruv2, (char *)ruv2name, NULL);
+ }
+
/* compare replica generations first */
if (ruv1->replGen == NULL || ruv2->replGen == NULL) {
slapi_log_error(loglevel, repl_plugin_name,
@@ -1347,7 +1369,17 @@ ruv_compare_ruv(const RUV *ruv1, const char *ruv1name, const RUV *ruv2, const ch
"than the max CSN [%s] from RUV [%s] for element [%s]\n",
csnstrb, ruvbname, csnstra, ruvaname, ruvelem);
rc = RUV_COMP_CSN_DIFFERS;
+ } else {
+ csn_as_string(replicaa->csn, PR_FALSE, csnstra);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_compare_ruv: the max CSN [%s] from RUV [%s] is less than "
+ "or equal to the max CSN [%s] from RUV [%s] for element [%s]\n",
+ csnstrb, ruvbname, csnstra, ruvaname, ruvelem);
}
+ } else {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_compare_ruv: RUV [%s] has an empty CSN\n",
+ ruvbname);
}
}
}
10 years, 11 months
Branch '389-ds-base-1.2.11' - ldap/servers
by Richard Allen Megginson
ldap/servers/plugins/replication/repl5_inc_protocol.c | 38 ++++++++++++++++++
ldap/servers/plugins/replication/repl5_ruv.c | 32 +++++++++++++++
2 files changed, 70 insertions(+)
New commits:
commit 0c194eb79aa381bf4e4cd05082956218512115a4
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Wed May 15 19:39:24 2013 -0600
Ticket #47362 - ipa upgrade selinuxusermap data not replicating
https://fedorahosted.org/389/ticket/47362
Reviewed by: nhosoi (Thanks!)
Branch: 389-ds-base-1.2.11
Fix Description: When nsslapd-port is set to 0, this causes the
replica purl to be "ldap://hostname:0". At startup, the MMR code looks to
see if this replica purl is in the RUV, by doing a string comparison of this
purl with the ruv replica purl. If it is not there, the MMR code wipes out
this ruv element. Later the code in replica_check_for_data_reload() uses
this RUV to see if it needs to reinit the changelog. Since the RUV doesn't
match the changelog RUV any more, the changelog is erased, which erases
any changes that were made in the meantime. The missing RUV element causes
the supplier to attempt to send over changes which may already exist on the
consumer. If one of these is an ADD, the urp code will correctly flag this
as an attempt to add an entry that already exists, and will turn this into
a replConflict entry. A subsequent attempt to replicate the same ADD will
cause an error in the urp code which will cause it to return err=53.
Replication will then become stuck on this update - it will keep trying to
send it over and over again, and will not be able to proceed.
The only workaround is a replica reinit of the replica, to get the database
RUV and changelog in a consistent state.
I've also added some additional RUV debugging when using the REPL log level.
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
index 743be57..82b121c 100644
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -1931,6 +1931,44 @@ repl5_inc_stop(Private_Repl_Protocol *prp)
agmt_get_long_name(prp->agmt),
PR_IntervalToSeconds(now-start));
}
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
+ if (NULL == prp->replica_object) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: protocol replica_object is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ Replica *replica;
+ object_acquire(prp->replica_object);
+ replica = object_get_data(prp->replica_object);
+ if (NULL == replica) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: replica is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ Object *ruv_obj = replica_get_ruv(replica);
+ if (NULL == ruv_obj) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: ruv_obj is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ RUV *ruv;
+ object_acquire(ruv_obj);
+ ruv = (RUV*)object_get_data (ruv_obj);
+ if (NULL == ruv) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: ruv is NULL\n",
+ agmt_get_long_name(prp->agmt));
+
+ } else {
+ ruv_dump(ruv, "Database RUV", NULL);
+ }
+ object_release(ruv_obj);
+ }
+ }
+ object_release(prp->replica_object);
+ }
+
+ }
return return_value;
}
diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c
index b52dd49..8fbd89c 100644
--- a/ldap/servers/plugins/replication/repl5_ruv.c
+++ b/ldap/servers/plugins/replication/repl5_ruv.c
@@ -208,6 +208,9 @@ ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *
Slapi_Value *value;
const struct berval *bval;
const char *purl = NULL;
+ char *localhost = get_localhost_DNS();
+ size_t localhostlen = localhost ? strlen(localhost) : 0;
+ int port = config_get_port();
return_value = RUV_SUCCESS;
@@ -236,16 +239,30 @@ ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *
RUVElement *ruve = get_ruvelement_from_berval(bval);
if (NULL != ruve)
{
+ char *ptr;
/* Is the local purl already in the ruv ? */
if ( (*contain_purl==0) && ruve->replica_purl && purl && (strncmp(ruve->replica_purl, purl, strlen(purl))==0) )
{
*contain_purl = ruve->rid;
}
+ /* ticket 47362 - nsslapd-port: 0 causes replication to break */
+ else if ((*contain_purl==0) && ruve->replica_purl && (port == 0) && localhost &&
+ (ptr = strstr(ruve->replica_purl, localhost)) && (ptr != ruve->replica_purl) &&
+ (*(ptr - 1) == '/') && (*(ptr+localhostlen) == ':'))
+ {
+ /* same hostname, but port number may have been temporarily set to 0
+ * just allow it with whatever port number is already in the replica_purl
+ * do not reset the port number, do not tell the configure_ruv code that there
+ * is anything wrong
+ */
+ *contain_purl = ruve->rid;
+ }
dl_add ((*ruv)->elements, ruve);
}
}
}
}
+ slapi_ch_free_string(&localhost);
}
}
return return_value;
@@ -1279,6 +1296,11 @@ ruv_compare_ruv(const RUV *ruv1, const char *ruv1name, const RUV *ruv2, const ch
const char *ruvbnames[] = {ruv2name, ruv1name};
const int nitems = 2;
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
+ ruv_dump(ruv1, (char *)ruv1name, NULL);
+ ruv_dump(ruv2, (char *)ruv2name, NULL);
+ }
+
/* compare replica generations first */
if (ruv1->replGen == NULL || ruv2->replGen == NULL) {
slapi_log_error(loglevel, repl_plugin_name,
@@ -1335,7 +1357,17 @@ ruv_compare_ruv(const RUV *ruv1, const char *ruv1name, const RUV *ruv2, const ch
"than the max CSN [%s] from RUV [%s] for element [%s]\n",
csnstrb, ruvbname, csnstra, ruvaname, ruvelem);
rc = RUV_COMP_CSN_DIFFERS;
+ } else {
+ csn_as_string(replicaa->csn, PR_FALSE, csnstra);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_compare_ruv: the max CSN [%s] from RUV [%s] is less than "
+ "or equal to the max CSN [%s] from RUV [%s] for element [%s]\n",
+ csnstrb, ruvbname, csnstra, ruvaname, ruvelem);
}
+ } else {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_compare_ruv: RUV [%s] has an empty CSN\n",
+ ruvbname);
}
}
}
10 years, 11 months
ldap/servers
by Richard Allen Megginson
ldap/servers/plugins/replication/repl5_inc_protocol.c | 38 ++++++++++++++++++
ldap/servers/plugins/replication/repl5_ruv.c | 32 +++++++++++++++
2 files changed, 70 insertions(+)
New commits:
commit 6236d7a7df86141311d731ce737d1c0986d564ee
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Wed May 15 19:39:24 2013 -0600
Ticket #47362 - ipa upgrade selinuxusermap data not replicating
https://fedorahosted.org/389/ticket/47362
Reviewed by: nhosoi (Thanks!)
Branch: master
Fix Description: When nsslapd-port is set to 0, this causes the
replica purl to be "ldap://hostname:0". At startup, the MMR code looks to
see if this replica purl is in the RUV, by doing a string comparison of this
purl with the ruv replica purl. If it is not there, the MMR code wipes out
this ruv element. Later the code in replica_check_for_data_reload() uses
this RUV to see if it needs to reinit the changelog. Since the RUV doesn't
match the changelog RUV any more, the changelog is erased, which erases
any changes that were made in the meantime. The missing RUV element causes
the supplier to attempt to send over changes which may already exist on the
consumer. If one of these is an ADD, the urp code will correctly flag this
as an attempt to add an entry that already exists, and will turn this into
a replConflict entry. A subsequent attempt to replicate the same ADD will
cause an error in the urp code which will cause it to return err=53.
Replication will then become stuck on this update - it will keep trying to
send it over and over again, and will not be able to proceed.
The only workaround is a replica reinit of the replica, to get the database
RUV and changelog in a consistent state.
I've also added some additional RUV debugging when using the REPL log level.
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
(cherry picked from commit 614ce4e4b1774526bb8c4ad6c43a1582adcc30ec)
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
index 72d2d6c..fa442fe 100644
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -1941,6 +1941,44 @@ repl5_inc_stop(Private_Repl_Protocol *prp)
agmt_get_long_name(prp->agmt),
PR_IntervalToSeconds(now-start));
}
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
+ if (NULL == prp->replica_object) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: protocol replica_object is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ Replica *replica;
+ object_acquire(prp->replica_object);
+ replica = object_get_data(prp->replica_object);
+ if (NULL == replica) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: replica is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ Object *ruv_obj = replica_get_ruv(replica);
+ if (NULL == ruv_obj) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: ruv_obj is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ RUV *ruv;
+ object_acquire(ruv_obj);
+ ruv = (RUV*)object_get_data (ruv_obj);
+ if (NULL == ruv) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: ruv is NULL\n",
+ agmt_get_long_name(prp->agmt));
+
+ } else {
+ ruv_dump(ruv, "Database RUV", NULL);
+ }
+ object_release(ruv_obj);
+ }
+ }
+ object_release(prp->replica_object);
+ }
+
+ }
return return_value;
}
diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c
index 9ce9768..107c4f0 100644
--- a/ldap/servers/plugins/replication/repl5_ruv.c
+++ b/ldap/servers/plugins/replication/repl5_ruv.c
@@ -208,6 +208,9 @@ ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *
Slapi_Value *value;
const struct berval *bval;
const char *purl = NULL;
+ char *localhost = get_localhost_DNS();
+ size_t localhostlen = localhost ? strlen(localhost) : 0;
+ int port = config_get_port();
return_value = RUV_SUCCESS;
@@ -236,16 +239,30 @@ ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *
RUVElement *ruve = get_ruvelement_from_berval(bval);
if (NULL != ruve)
{
+ char *ptr;
/* Is the local purl already in the ruv ? */
if ( (*contain_purl==0) && ruve->replica_purl && purl && (strncmp(ruve->replica_purl, purl, strlen(purl))==0) )
{
*contain_purl = ruve->rid;
}
+ /* ticket 47362 - nsslapd-port: 0 causes replication to break */
+ else if ((*contain_purl==0) && ruve->replica_purl && (port == 0) && localhost &&
+ (ptr = strstr(ruve->replica_purl, localhost)) && (ptr != ruve->replica_purl) &&
+ (*(ptr - 1) == '/') && (*(ptr+localhostlen) == ':'))
+ {
+ /* same hostname, but port number may have been temporarily set to 0
+ * just allow it with whatever port number is already in the replica_purl
+ * do not reset the port number, do not tell the configure_ruv code that there
+ * is anything wrong
+ */
+ *contain_purl = ruve->rid;
+ }
dl_add ((*ruv)->elements, ruve);
}
}
}
}
+ slapi_ch_free_string(&localhost);
}
}
return return_value;
@@ -1291,6 +1308,11 @@ ruv_compare_ruv(const RUV *ruv1, const char *ruv1name, const RUV *ruv2, const ch
const char *ruvbnames[] = {ruv2name, ruv1name};
const int nitems = 2;
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
+ ruv_dump(ruv1, (char *)ruv1name, NULL);
+ ruv_dump(ruv2, (char *)ruv2name, NULL);
+ }
+
/* compare replica generations first */
if (ruv1->replGen == NULL || ruv2->replGen == NULL) {
slapi_log_error(loglevel, repl_plugin_name,
@@ -1347,7 +1369,17 @@ ruv_compare_ruv(const RUV *ruv1, const char *ruv1name, const RUV *ruv2, const ch
"than the max CSN [%s] from RUV [%s] for element [%s]\n",
csnstrb, ruvbname, csnstra, ruvaname, ruvelem);
rc = RUV_COMP_CSN_DIFFERS;
+ } else {
+ csn_as_string(replicaa->csn, PR_FALSE, csnstra);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_compare_ruv: the max CSN [%s] from RUV [%s] is less than "
+ "or equal to the max CSN [%s] from RUV [%s] for element [%s]\n",
+ csnstrb, ruvbname, csnstra, ruvaname, ruvelem);
}
+ } else {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_compare_ruv: RUV [%s] has an empty CSN\n",
+ ruvbname);
}
}
}
10 years, 11 months
Branch '389-ds-base-1.3.0' - ldap/servers
by Richard Allen Megginson
ldap/servers/plugins/replication/repl5_inc_protocol.c | 38 ++++++++++++++++++
ldap/servers/plugins/replication/repl5_ruv.c | 32 +++++++++++++++
2 files changed, 70 insertions(+)
New commits:
commit 2777aefc12fd5555f0787eaae3180d824404c931
Author: Rich Megginson <rmeggins(a)redhat.com>
Date: Wed May 15 19:39:24 2013 -0600
Ticket #47362 - ipa upgrade selinuxusermap data not replicating
https://fedorahosted.org/389/ticket/47362
Reviewed by: nhosoi (Thanks!)
Branch: 389-ds-base-1.3.0
Fix Description: When nsslapd-port is set to 0, this causes the
replica purl to be "ldap://hostname:0". At startup, the MMR code looks to
see if this replica purl is in the RUV, by doing a string comparison of this
purl with the ruv replica purl. If it is not there, the MMR code wipes out
this ruv element. Later the code in replica_check_for_data_reload() uses
this RUV to see if it needs to reinit the changelog. Since the RUV doesn't
match the changelog RUV any more, the changelog is erased, which erases
any changes that were made in the meantime. The missing RUV element causes
the supplier to attempt to send over changes which may already exist on the
consumer. If one of these is an ADD, the urp code will correctly flag this
as an attempt to add an entry that already exists, and will turn this into
a replConflict entry. A subsequent attempt to replicate the same ADD will
cause an error in the urp code which will cause it to return err=53.
Replication will then become stuck on this update - it will keep trying to
send it over and over again, and will not be able to proceed.
The only workaround is a replica reinit of the replica, to get the database
RUV and changelog in a consistent state.
I've also added some additional RUV debugging when using the REPL log level.
Platforms tested: RHEL6 x86_64
Flag Day: no
Doc impact: no
(cherry picked from commit 614ce4e4b1774526bb8c4ad6c43a1582adcc30ec)
(cherry picked from commit 6236d7a7df86141311d731ce737d1c0986d564ee)
diff --git a/ldap/servers/plugins/replication/repl5_inc_protocol.c b/ldap/servers/plugins/replication/repl5_inc_protocol.c
index 743be57..82b121c 100644
--- a/ldap/servers/plugins/replication/repl5_inc_protocol.c
+++ b/ldap/servers/plugins/replication/repl5_inc_protocol.c
@@ -1931,6 +1931,44 @@ repl5_inc_stop(Private_Repl_Protocol *prp)
agmt_get_long_name(prp->agmt),
PR_IntervalToSeconds(now-start));
}
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
+ if (NULL == prp->replica_object) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: protocol replica_object is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ Replica *replica;
+ object_acquire(prp->replica_object);
+ replica = object_get_data(prp->replica_object);
+ if (NULL == replica) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: replica is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ Object *ruv_obj = replica_get_ruv(replica);
+ if (NULL == ruv_obj) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: ruv_obj is NULL\n",
+ agmt_get_long_name(prp->agmt));
+ } else {
+ RUV *ruv;
+ object_acquire(ruv_obj);
+ ruv = (RUV*)object_get_data (ruv_obj);
+ if (NULL == ruv) {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "%s: repl5_inc_stop: ruv is NULL\n",
+ agmt_get_long_name(prp->agmt));
+
+ } else {
+ ruv_dump(ruv, "Database RUV", NULL);
+ }
+ object_release(ruv_obj);
+ }
+ }
+ object_release(prp->replica_object);
+ }
+
+ }
return return_value;
}
diff --git a/ldap/servers/plugins/replication/repl5_ruv.c b/ldap/servers/plugins/replication/repl5_ruv.c
index b52dd49..8fbd89c 100644
--- a/ldap/servers/plugins/replication/repl5_ruv.c
+++ b/ldap/servers/plugins/replication/repl5_ruv.c
@@ -208,6 +208,9 @@ ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *
Slapi_Value *value;
const struct berval *bval;
const char *purl = NULL;
+ char *localhost = get_localhost_DNS();
+ size_t localhostlen = localhost ? strlen(localhost) : 0;
+ int port = config_get_port();
return_value = RUV_SUCCESS;
@@ -236,16 +239,30 @@ ruv_init_from_slapi_attr_and_check_purl(Slapi_Attr *attr, RUV **ruv, ReplicaId *
RUVElement *ruve = get_ruvelement_from_berval(bval);
if (NULL != ruve)
{
+ char *ptr;
/* Is the local purl already in the ruv ? */
if ( (*contain_purl==0) && ruve->replica_purl && purl && (strncmp(ruve->replica_purl, purl, strlen(purl))==0) )
{
*contain_purl = ruve->rid;
}
+ /* ticket 47362 - nsslapd-port: 0 causes replication to break */
+ else if ((*contain_purl==0) && ruve->replica_purl && (port == 0) && localhost &&
+ (ptr = strstr(ruve->replica_purl, localhost)) && (ptr != ruve->replica_purl) &&
+ (*(ptr - 1) == '/') && (*(ptr+localhostlen) == ':'))
+ {
+ /* same hostname, but port number may have been temporarily set to 0
+ * just allow it with whatever port number is already in the replica_purl
+ * do not reset the port number, do not tell the configure_ruv code that there
+ * is anything wrong
+ */
+ *contain_purl = ruve->rid;
+ }
dl_add ((*ruv)->elements, ruve);
}
}
}
}
+ slapi_ch_free_string(&localhost);
}
}
return return_value;
@@ -1279,6 +1296,11 @@ ruv_compare_ruv(const RUV *ruv1, const char *ruv1name, const RUV *ruv2, const ch
const char *ruvbnames[] = {ruv2name, ruv1name};
const int nitems = 2;
+ if (slapi_is_loglevel_set(SLAPI_LOG_REPL)) {
+ ruv_dump(ruv1, (char *)ruv1name, NULL);
+ ruv_dump(ruv2, (char *)ruv2name, NULL);
+ }
+
/* compare replica generations first */
if (ruv1->replGen == NULL || ruv2->replGen == NULL) {
slapi_log_error(loglevel, repl_plugin_name,
@@ -1335,7 +1357,17 @@ ruv_compare_ruv(const RUV *ruv1, const char *ruv1name, const RUV *ruv2, const ch
"than the max CSN [%s] from RUV [%s] for element [%s]\n",
csnstrb, ruvbname, csnstra, ruvaname, ruvelem);
rc = RUV_COMP_CSN_DIFFERS;
+ } else {
+ csn_as_string(replicaa->csn, PR_FALSE, csnstra);
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_compare_ruv: the max CSN [%s] from RUV [%s] is less than "
+ "or equal to the max CSN [%s] from RUV [%s] for element [%s]\n",
+ csnstrb, ruvbname, csnstra, ruvaname, ruvelem);
}
+ } else {
+ slapi_log_error(SLAPI_LOG_REPL, repl_plugin_name,
+ "ruv_compare_ruv: RUV [%s] has an empty CSN\n",
+ ruvbname);
}
}
}
10 years, 11 months
ldap/admin ldap/servers
by thierry bordaz
ldap/admin/src/logconv.pl | 221 +++++++++++++++++++++++------
ldap/servers/slapd/back-ldbm/ldbm_search.c | 6
ldap/servers/slapd/result.c | 3
ldap/servers/slapd/slapi-plugin.h | 1
4 files changed, 187 insertions(+), 44 deletions(-)
New commits:
commit f2b5a975c2268b6e99bf27b45a7380d295807d81
Author: Thierry bordaz (tbordaz) <tbordaz(a)redhat.com>
Date: Fri May 17 11:48:08 2013 +0200
Ticket 47354 - Indexed search are logged with 'notes=U' in the access logs
Bug Description:
In the access log, the flag "notes=U" is present to warn the customer that the provided filter contains not
indexed components. This flag is set independently of the fact that all entries of the database will be
evaluated against the filter. So it can not be used to determine if all the entries have been scanned.
Evaluated all entries is usually a performance hit for large database containing millions of entries.
Fix Description:
The fix consist to introduce a new flag 'notes=A' at the top level (ldbm_back_search) only when the candidate
list is ALLID and all entries will be scanned.
The fix also contains the update of logconv.pl to take into account this change.
https://fedorahosted.org/389/ticket/47354
Reviewed by: Rich Megginson and Mark Reynolds (thanks to you !)
Platforms tested: Fedora 17
Flag Day: no
Doc impact: no
diff --git a/ldap/admin/src/logconv.pl b/ldap/admin/src/logconv.pl
index efc5970..bac28ef 100755
--- a/ldap/admin/src/logconv.pl
+++ b/ldap/admin/src/logconv.pl
@@ -157,8 +157,10 @@ print "\nCommand: logconv.pl @ARGV\n\n";
$rootDNBindCount = 0;
$anonymousBindCount = 0;
-$unindexedSrchCount = 0;
-$vlvNotesCount= 0;
+$unindexedSrchCountNotesA = 0;
+$unindexedSrchCountNotesU = 0;
+$vlvNotesACount= 0;
+$vlvNotesUCount= 0;
$srchCount = 0;
$fdTaken = 0;
$fdReturned = 0;
@@ -254,11 +256,16 @@ $UNBIND_CONN = "$dataLocation/unbindconn.logconv";
$UNBIND_OP = "$dataLocation/unbindop.logconv";
$EXT_CONN = "$dataLocation/extconn.logconv";
$EXT_OP = "$dataLocation/extop.logconv";
-$NOTES_ETIME = "$dataLocation/notesetime.logconv";
-$NOTES_CONN = "$dataLocation/notesconn.logconv";
-$NOTES_OP = "$dataLocation/notesop.logconv";
-$NOTES_TIME = "$dataLocation/notestime.logconv";
-$NOTES_NENTRIES = "$dataLocation/notesnentries.logconv";
+$NOTES_A_ETIME = "$dataLocation/notesAetime.logconv";
+$NOTES_A_CONN = "$dataLocation/notesAconn.logconv";
+$NOTES_A_OP = "$dataLocation/notesAop.logconv";
+$NOTES_A_TIME = "$dataLocation/notesAtime.logconv";
+$NOTES_A_NENTRIES = "$dataLocation/notesAnentries.logconv";
+$NOTES_U_ETIME = "$dataLocation/notesUetime.logconv";
+$NOTES_U_CONN = "$dataLocation/notesUconn.logconv";
+$NOTES_U_OP = "$dataLocation/notesUop.logconv";
+$NOTES_U_TIME = "$dataLocation/notesUtime.logconv";
+$NOTES_U_NENTRIES = "$dataLocation/notesUnentries.logconv";
$BADPWDCONN = "$dataLocation/badpwdconn.logconv";
$BADPWDOP = "$dataLocation/badpwdop.logconv";
$BADPWDIP = "$dataLocation/badpwdip.logconv";
@@ -641,20 +648,22 @@ print "Abandoned Requests: $abandonCount\n";
print "Smart Referrals Received: $referralCount\n";
print "\n";
print "VLV Operations: $vlvCount\n";
-print "VLV Unindexed Searches: $vlvNotesCount\n";
+print "VLV Unindexed Searches: $vlvNotesACount\n";
+print "VLV Unindexed Components: $vlvNotesUCount\n";
print "SORT Operations: $vlvSortCount\n";
print "\n";
print "Entire Search Base Queries: $objectclassTopCount\n";
print "Paged Searches: $pagedSearchCount\n";
-print "Unindexed Searches: $unindexedSrchCount\n";
+print "Unindexed Searches: $unindexedSrchCountNotesA\n";
+print "Unindexed Components: $unindexedSrchCountNotesU\n";
if ($verb eq "yes" || $usage =~ /u/){
- if ($unindexedSrchCount > 0){
+ if ($unindexedSrchCountNotesA > 0){
%conn_hash = getHashFromFile($CONN_HASH);
- @notesConn = getArrayFromFile($NOTES_CONN);
- @notesOp = getArrayFromFile($NOTES_OP);
- @notesEtime = getArrayFromFile($NOTES_ETIME);
- @notesTime = getArrayFromFile($NOTES_TIME);
- @notesNentries = getArrayFromFile($NOTES_NENTRIES);
+ @notesConn = getArrayFromFile($NOTES_A_CONN);
+ @notesOp = getArrayFromFile($NOTES_A_OP);
+ @notesEtime = getArrayFromFile($NOTES_A_ETIME);
+ @notesTime = getArrayFromFile($NOTES_A_TIME);
+ @notesNentries = getArrayFromFile($NOTES_A_NENTRIES);
getInfoArraysFromFile($BASEINFO);
@base_val = @fileArray1;
@base_conn = @fileArray2;
@@ -720,6 +729,78 @@ if ($verb eq "yes" || $usage =~ /u/){
undef @scope_conn;
undef @scope_op;
}
+ if ($unindexedSrchCountNotesU > 0){
+ %conn_hash = getHashFromFile($CONN_HASH);
+ @notesConn = getArrayFromFile($NOTES_U_CONN);
+ @notesOp = getArrayFromFile($NOTES_U_OP);
+ @notesEtime = getArrayFromFile($NOTES_U_ETIME);
+ @notesTime = getArrayFromFile($NOTES_U_TIME);
+ @notesNentries = getArrayFromFile($NOTES_U_NENTRIES);
+ getInfoArraysFromFile($BASEINFO);
+ @base_val = @fileArray1;
+ @base_conn = @fileArray2;
+ @base_op = @fileArray3;
+ getInfoArraysFromFile($SCOPEINFO);
+ @scope_val = @fileArray1;
+ @scope_conn = @fileArray2;
+ @scope_op = @fileArray3;
+ getInfoArraysFromFile($FILTERINFO);
+ @filter_val = @fileArray1;
+ @filter_conn = @fileArray2;
+ @filter_op = @fileArray3;
+
+ $notesCount = "1";
+ for ($n = 0; $n <= $#notesEtime; $n++){
+ @alreadyseenDN = ();
+ if($conn_hash{$notesConn[$n]} eq ""){
+ $unindexedIp = "?";
+ } else {
+ $unindexedIp = $conn_hash{$notesConn[$n]};
+ }
+ print "\n Unindexed Components #".$notesCount."\n"; $notesCount++;
+ print " - Date/Time: $notesTime[$n]\n";
+ print " - Connection Number: $notesConn[$n]\n";
+ print " - Operation Number: $notesOp[$n]\n";
+ print " - Etime: $notesEtime[$n]\n";
+ print " - Nentries: $notesNentries[$n]\n";
+ print " - IP Address: $unindexedIp\n";
+
+ for ($nnn = 0; $nnn < $baseCount; $nnn++){
+ if ($notesConn[$n] eq $base_conn[$nnn] && $notesOp[$n] eq $base_op[$nnn]){
+ print " - Search Base: $base_val[$nnn]\n";
+ last;
+ }
+ }
+ for ($nnn = 0; $nnn < $scopeCount; $nnn++){
+ if ($notesConn[$n] eq $scope_conn[$nnn] && $notesOp[$n] eq $scope_op[$nnn]){
+ print " - Search Scope: $scope_val[$nnn]\n";
+ last;
+ }
+ }
+ for ($nnn = 0; $nnn < $filterCount; $nnn++){
+ if ($notesConn[$n] eq $filter_conn[$nnn] && $notesOp[$n] eq $filter_op[$nnn]){
+ print " - Search Filter: $filter_val[$nnn]\n";
+ last;
+ }
+ }
+ }
+ undef %conn_hash;
+ undef @notesConn;
+ undef @notesOp;
+ undef @notesEtime;
+ undef @notesTime;
+ undef @notesNentries;
+ undef @notesIp;
+ undef @filter_val;
+ undef @filter_conn;
+ undef @filter_op;
+ undef @base_val;
+ undef @base_conn;
+ undef @base_op;
+ undef @scope_val;
+ undef @scope_conn;
+ undef @scope_op;
+ }
} # end of unindexed search report
print "\n";
@@ -1276,10 +1357,14 @@ if ($usage =~ /j/i || $verb eq "yes"){
%conncount = getCounterHashFromFile($CONNCOUNT);
print "\n----- Recommendations -----\n";
$recCount = "1";
- if ($unindexedSrchCount > 0){
+ if ($unindexedSrchCountNotesA > 0){
print "\n $recCount. You have unindexed searches, this can be caused from a search on an unindexed attribute, or your returned results exceeded the allidsthreshold. Unindexed searches are not recommended. To refuse unindexed searches, switch \'nsslapd-require-index\' to \'on\' under your database entry (e.g. cn=UserRoot,cn=ldbm database,cn=plugins,cn=config).\n";
$recCount++;
}
+ if ($unindexedSrchCountNotesU > 0){
+ print "\n $recCount. You have unindexed components, this can be caused from a search on an unindexed attribute, or your returned results exceeded the allidsthreshold. Unindexed components are not recommended. To refuse unindexed searches, switch \'nsslapd-require-index\' to \'on\' under your database entry (e.g. cn=UserRoot,cn=ldbm database,cn=plugins,cn=config).\n";
+ $recCount++;
+ }
if ($conncount{"T1"} > 0){
print "\n $recCount. You have some connections that are are being closed by the idletimeout setting. You may want to increase the idletimeout if it is set low.\n";
$recCount++;
@@ -1773,36 +1858,71 @@ sub parseLineNormal
if (m/ RESULT err=/ && m/ notes=P/){
$pagedSearchCount++;
}
+ if (m/ notes=A/){
+ if ($_ =~ /conn= *([0-9]+)/i){
+ $con = $1;
+ if ($_ =~ /op= *([0-9]+)/i){ $op = $1;}
+ }
+ for ($i=0; $i <= $vlvCount;$i++){
+ if ($vlvconn[$i] eq $con && $vlvop[$i] eq $op){ $vlvNotesACount++; $isVlvNotes="1";}
+ }
+ if($isVlvNotes == 0){
+ # We don't want to record vlv unindexed searches for our regular "bad"
+ # unindexed search stat, as VLV unindexed searches aren't that bad
+ $unindexedSrchCountNotesA++;
+ if($reportStats){ inc_stats('notesA',$s_stats,$m_stats); }
+ }
+ if ($usage =~ /u/ || $verb eq "yes"){
+ if ($isVlvNnotes == 0 ){
+ if ($_ =~ /etime= *([0-9.]+)/i ){
+ writeFile($NOTES_A_ETIME, $1);
+ }
+ if ($_ =~ /conn= *([0-9]+)/i){
+ writeFile($NOTES_A_CONN, $1);
+ }
+ if ($_ =~ /op= *([0-9]+)/i){
+ writeFile($NOTES_A_OP, $1);
+ }
+ if ($_ =~ / *([0-9a-z:\/]+)/i){
+ writeFile($NOTES_A_TIME, $1);
+ }
+ if ($_ =~ /nentries= *([0-9]+)/i ){
+ writeFile($NOTES_A_NENTRIES, $1);
+ }
+ }
+ }
+ $isVlvNotes = 0;
+ }
if (m/ notes=U/){
if ($_ =~ /conn= *([0-9]+)/i){
$con = $1;
if ($_ =~ /op= *([0-9]+)/i){ $op = $1;}
}
for ($i=0; $i <= $vlvCount;$i++){
- if ($vlvconn[$i] eq $con && $vlvop[$i] eq $op){ $vlvNotesCount++; $isVlvNotes="1";}
+ if ($vlvconn[$i] eq $con && $vlvop[$i] eq $op){ $vlvNotesUCount++; $isVlvNotes="1";}
}
if($isVlvNotes == 0){
# We don't want to record vlv unindexed searches for our regular "bad"
# unindexed search stat, as VLV unindexed searches aren't that bad
- $unindexedSrchCount++;
- if($reportStats){ inc_stats('notesu',$s_stats,$m_stats); }
+ $unindexedSrchCountNotesU++;
+ if($reportStats){ inc_stats('notesU',$s_stats,$m_stats); }
}
if ($usage =~ /u/ || $verb eq "yes"){
if ($isVlvNnotes == 0 ){
if ($_ =~ /etime= *([0-9.]+)/i ){
- writeFile($NOTES_ETIME, $1);
+ writeFile($NOTES_U_ETIME, $1);
}
if ($_ =~ /conn= *([0-9]+)/i){
- writeFile($NOTES_CONN, $1);
+ writeFile($NOTES_U_CONN, $1);
}
if ($_ =~ /op= *([0-9]+)/i){
- writeFile($NOTES_OP, $1);
+ writeFile($NOTES_U_OP, $1);
}
if ($_ =~ / *([0-9a-z:\/]+)/i){
- writeFile($NOTES_TIME, $1);
+ writeFile($NOTES_U_TIME, $1);
}
if ($_ =~ /nentries= *([0-9]+)/i ){
- writeFile($NOTES_NENTRIES, $1);
+ writeFile($NOTES_U_NENTRIES, $1);
}
}
}
@@ -2196,7 +2316,8 @@ reset_stats_block
$stats->{'bind'}=0;
$stats->{'anonbind'}=0;
$stats->{'unbind'}=0;
- $stats->{'notesu'}=0;
+ $stats->{'notesA'}=0;
+ $stats->{'notesU'}=0;
$stats->{'etime'}=0;
return;
}
@@ -2242,13 +2363,14 @@ print_stats_block
$stats->{'bind'},
$stats->{'anonbind'},
$stats->{'unbind'},
- $stats->{'notesu'},
+ $stats->{'notesA'},
+ $stats->{'notesU'},
$stats->{'etime'}),
"\n" );
} else {
$stats->{'fh'}->print(
"Time,time_t,Results,Search,Add,Mod,Modrdn,Moddn,Compare,Delete,Abandon,".
- "Connections,SSL Conns,Bind,Anon Bind,Unbind,Unindexed,ElapsedTime\n"
+ "Connections,SSL Conns,Bind,Anon Bind,Unbind,Unindexed search,Unindexed component,ElapsedTime\n"
);
}
}
@@ -2415,11 +2537,16 @@ openDataFiles
open($UNBIND_OP, ">$UNBIND_OP") or do { openFailed($!, $UNBIND_OP) };
open($EXT_CONN, ">$EXT_CONN") or do { openFailed($!, $EXT_CONN) };
open($EXT_OP, ">$EXT_OP") or do { openFailed($!, $EXT_OP) };
- open($NOTES_ETIME, ">$NOTES_ETIME") or do { openFailed($!, $NOTES_ETIME) };
- open($NOTES_CONN, ">$NOTES_CONN") or do { openFailed($!, $NOTES_CONN) };
- open($NOTES_OP, ">$NOTES_OP") or do { openFailed($!, $NOTES_OP) };
- open($NOTES_TIME, ">$NOTES_TIME") or do { openFailed($!, $NOTES_TIME) };
- open($NOTES_NENTRIES, ">$NOTES_NENTRIES") or do { openFailed($!, $NOTES_NENTRIES) };
+ open($NOTES_A_ETIME, ">$NOTES_A_ETIME") or do { openFailed($!, $NOTES_A_ETIME) };
+ open($NOTES_A_CONN, ">$NOTES_A_CONN") or do { openFailed($!, $NOTES_A_CONN) };
+ open($NOTES_A_OP, ">$NOTES_A_OP") or do { openFailed($!, $NOTES_A_OP) };
+ open($NOTES_A_TIME, ">$NOTES_A_TIME") or do { openFailed($!, $NOTES_A_TIME) };
+ open($NOTES_A_NENTRIES, ">$NOTES_A_NENTRIES") or do { openFailed($!, $NOTES_A_NENTRIES) };
+ open($NOTES_U_ETIME, ">$NOTES_U_ETIME") or do { openFailed($!, $NOTES_U_ETIME) };
+ open($NOTES_U_CONN, ">$NOTES_U_CONN") or do { openFailed($!, $NOTES_U_CONN) };
+ open($NOTES_U_OP, ">$NOTES_U_OP") or do { openFailed($!, $NOTES_U_OP) };
+ open($NOTES_U_TIME, ">$NOTES_U_TIME") or do { openFailed($!, $NOTES_U_TIME) };
+ open($NOTES_U_NENTRIES, ">$NOTES_U_NENTRIES") or do { openFailed($!, $NOTES_U_NENTRIES) };
open($BADPWDCONN, ">$BADPWDCONN") or do { openFailed($!, $BADPWDCONN) };
open($BADPWDOP, ">$BADPWDOP") or do { openFailed($!, $BADPWDOP) };
open($BADPWDIP, ">$BADPWDIP") or do { openFailed($!, $NADPWDIP) };
@@ -2473,11 +2600,16 @@ closeDataFiles
close $UNBIND_OP;
close $EXT_CONN;
close $EXT_OP;
- close $NOTES_ETIME;
- close $NOTES_CONN;
- close $NOTES_OP;
- close $NOTES_TIME;
- close $NOTES_NENTRIES;
+ close $NOTES_A_ETIME;
+ close $NOTES_A_CONN;
+ close $NOTES_A_OP;
+ close $NOTES_A_TIME;
+ close $NOTES_A_NENTRIES;
+ close $NOTES_U_ETIME;
+ close $NOTES_U_CONN;
+ close $NOTES_U_OP;
+ close $NOTES_U_TIME;
+ close $NOTES_U_NENTRIES;
close $BADPWDCONN;
close $BADPWDOP;
close $BADPWDIP;
@@ -2531,11 +2663,16 @@ removeDataFiles
unlink $UNBIND_OP;
unlink $EXT_CONN;
unlink $EXT_OP;
- unlink $NOTES_ETIME;
- unlink $NOTES_CONN;
- unlink $NOTES_OP;
- unlink $NOTES_TIME;
- unlink $NOTES_NENTRIES;
+ unlink $NOTES_A_ETIME;
+ unlink $NOTES_A_CONN;
+ unlink $NOTES_A_OP;
+ unlink $NOTES_A_TIME;
+ unlink $NOTES_A_NENTRIES;
+ unlink $NOTES_U_ETIME;
+ unlink $NOTES_U_CONN;
+ unlink $NOTES_U_OP;
+ unlink $NOTES_U_TIME;
+ unlink $NOTES_U_NENTRIES;
unlink $BADPWDCONN;
unlink $BADPWDOP;
unlink $BADPWDIP;
diff --git a/ldap/servers/slapd/back-ldbm/ldbm_search.c b/ldap/servers/slapd/back-ldbm/ldbm_search.c
index be4b63c..00cce2c 100644
--- a/ldap/servers/slapd/back-ldbm/ldbm_search.c
+++ b/ldap/servers/slapd/back-ldbm/ldbm_search.c
@@ -869,7 +869,7 @@ ldbm_back_search( Slapi_PBlock *pb )
* to record that fact.
*/
if ( NULL != candidates && ALLIDS( candidates )) {
- unsigned int opnote = SLAPI_OP_NOTE_UNINDEXED;
+ unsigned int opnote;
int ri = 0;
int pr_idx = -1;
@@ -892,6 +892,10 @@ ldbm_back_search( Slapi_PBlock *pb )
}
}
+ slapi_pblock_get( pb, SLAPI_OPERATION_NOTES, &opnote );
+ opnote |= SLAPI_OP_NOTE_FULL_UNINDEXED; /* the full filter leads to an unindexed search */
+ opnote &= ~SLAPI_OP_NOTE_UNINDEXED; /* this note is useless because FULL_UNINDEXED includes UNINDEXED */
+ slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, NULL );
slapi_pblock_set( pb, SLAPI_OPERATION_NOTES, &opnote );
slapi_pblock_get( pb, SLAPI_PAGED_RESULTS_INDEX, &pr_idx );
pagedresults_set_unindexed( pb->pb_conn, pb->pb_op, pr_idx );
diff --git a/ldap/servers/slapd/result.c b/ldap/servers/slapd/result.c
index e124d0b..8f64dd7 100644
--- a/ldap/servers/slapd/result.c
+++ b/ldap/servers/slapd/result.c
@@ -1617,7 +1617,8 @@ struct slapi_note_map {
static struct slapi_note_map notemap[] = {
{ SLAPI_OP_NOTE_UNINDEXED, "U" },
- { SLAPI_OP_NOTE_SIMPLEPAGED, "P" }
+ { SLAPI_OP_NOTE_SIMPLEPAGED, "P" },
+ { SLAPI_OP_NOTE_FULL_UNINDEXED, "A" }
};
#define SLAPI_NOTEMAP_COUNT ( sizeof(notemap) / sizeof(struct slapi_note_map))
diff --git a/ldap/servers/slapd/slapi-plugin.h b/ldap/servers/slapd/slapi-plugin.h
index ffcc928..2d618e9 100644
--- a/ldap/servers/slapd/slapi-plugin.h
+++ b/ldap/servers/slapd/slapi-plugin.h
@@ -6747,6 +6747,7 @@ typedef struct slapi_plugindesc {
#define SLAPI_OPERATION_NOTES 57
#define SLAPI_OP_NOTE_UNINDEXED 0x01
#define SLAPI_OP_NOTE_SIMPLEPAGED 0x02
+#define SLAPI_OP_NOTE_FULL_UNINDEXED 0x04
/* Allows controls to be passed before operation object is created */
#define SLAPI_CONTROLS_ARG 58
10 years, 11 months
Branch '389-ds-base-1.2.11' - ldap/servers
by thierry bordaz
ldap/servers/slapd/control.c | 32 +++++++++++++++++++++-----------
1 file changed, 21 insertions(+), 11 deletions(-)
New commits:
commit 76c87bd8c4d8b075b9615858b74f2caf7a95b2d5
Author: Thierry bordaz (tbordaz) <tbordaz(a)redhat.com>
Date: Thu May 16 15:28:47 2013 +0200
Ticket 47361 - Empty control list causes LDAP protocol error is thrown
Bug Description:
If a request contains a list of controls containing zero control, it does
not conform RFC http://tools.ietf.org/html/rfc4511#section-4.1.11. Then the
server returns a Protocol Error.
This is too restrictive for some applications.
Note: such application needs to be linked with old version of mozldap or openldap
because recent version skip sending empty list of controls
Fix Description:
The fix is to ignore this error and let the operation complete
https://fedorahosted.org/389/ticket/47361
Reviewed by: Rich Megginson (thanks Rich !)
Platforms tested: F17 (unit + acceptance vlv/proxy/managed/psearch/tls/bindcontrol)
Flag Day: no
Doc impact: no
diff --git a/ldap/servers/slapd/control.c b/ldap/servers/slapd/control.c
index fc3ab9f..e614d50 100644
--- a/ldap/servers/slapd/control.c
+++ b/ldap/servers/slapd/control.c
@@ -354,17 +354,27 @@ get_ldapmessage_controls_ext(
len = -1; /* reset for next loop iter */
}
- if ( (tag != LBER_END_OF_SEQORSET) && (len != -1) ) {
- goto free_and_return;
- }
-
- slapi_pblock_set( pb, SLAPI_REQCONTROLS, ctrls );
- managedsait = slapi_control_present( ctrls,
- LDAP_CONTROL_MANAGEDSAIT, NULL, NULL );
- slapi_pblock_set( pb, SLAPI_MANAGEDSAIT, &managedsait );
- pwpolicy_ctrl = slapi_control_present( ctrls,
- LDAP_X_CONTROL_PWPOLICY_REQUEST, NULL, NULL );
- slapi_pblock_set( pb, SLAPI_PWPOLICY, &pwpolicy_ctrl );
+ if (curcontrols == 0) {
+ int ctrl_not_found = 0; /* means that a given control is not present in the request */
+
+ slapi_pblock_set(pb, SLAPI_REQCONTROLS, NULL);
+ slapi_pblock_set(pb, SLAPI_MANAGEDSAIT, &ctrl_not_found);
+ slapi_pblock_set(pb, SLAPI_PWPOLICY, &ctrl_not_found);
+ slapi_log_error(SLAPI_LOG_CONNS, "connection", "Warning: conn=%d op=%d contains an empty list of controls\n",
+ pb->pb_conn->c_connid, pb->pb_op->o_opid);
+ } else {
+ if ((tag != LBER_END_OF_SEQORSET) && (len != -1)) {
+ goto free_and_return;
+ }
+
+ slapi_pblock_set(pb, SLAPI_REQCONTROLS, ctrls);
+ managedsait = slapi_control_present(ctrls,
+ LDAP_CONTROL_MANAGEDSAIT, NULL, NULL);
+ slapi_pblock_set(pb, SLAPI_MANAGEDSAIT, &managedsait);
+ pwpolicy_ctrl = slapi_control_present(ctrls,
+ LDAP_X_CONTROL_PWPOLICY_REQUEST, NULL, NULL);
+ slapi_pblock_set(pb, SLAPI_PWPOLICY, &pwpolicy_ctrl);
+ }
if ( controlsp != NULL ) {
*controlsp = ctrls;
10 years, 11 months
passwordsync/passhand.cpp passwordsync/passhand.h passwordsync/passhook passwordsync/passsync
by Noriko Hosoi
passwordsync/passhand.cpp | 13 +++
passwordsync/passhand.h | 1
passwordsync/passhook/passhook.cpp | 150 +++++++++++++++++++++++++++++--------
passwordsync/passsync/syncserv.cpp | 21 +++--
4 files changed, 145 insertions(+), 40 deletions(-)
New commits:
commit 130cb2003ebdfe04b3bc2794a250acc8540fd8b3
Author: Noriko Hosoi <nhosoi(a)redhat.com>
Date: Wed May 15 15:13:08 2013 -0700
Ticket #363 - Passsync/Winsync handles passwords with 8-th bit characters incorrectly
Bug description: Passhook plugin used to store the password in
the intermediate file passhook.dat using _snprintf which just
converts wchar in ascii to char without considering the non-
ascii characters.
Fix description: Instead of using _snprintf, WideCharToMultiByte
is called to convert the Microsoft internal character set to
UTF-8, which is valid in LDAP.
Also, in SyncPasswords (PassSync), it adds LDAP_INAPPROPRIATE_
AUTH to the condition to send the password change on Windows to
the Directory server. Bind returns LDAP_INAPPROPRIATE_AUTH,
when a password is not in the entry for SIMPLE auth. PassSync
should be able to send the password for the case, as well.
https://fedorahosted.org/389/ticket/363
Reviewed by Rich (Thanks!!)
diff --git a/passwordsync/passhand.cpp b/passwordsync/passhand.cpp
index f9b39bd..bbc006f 100644
--- a/passwordsync/passhand.cpp
+++ b/passwordsync/passhand.cpp
@@ -56,6 +56,19 @@ void timeStamp(fstream* outFile)
}
}
+void wtimeStamp(wfstream* outFile)
+{
+ if(outFile->is_open())
+ {
+ char dateBuf[32];
+ char timeBuf[32];
+
+ _strdate(dateBuf);
+ _strtime(timeBuf);
+ *outFile << dateBuf << " " << timeBuf << ": ";
+ }
+}
+
int saveSet(PASS_INFO_LIST* passInfoList, char* filename)
{
int result = 0;
diff --git a/passwordsync/passhand.h b/passwordsync/passhand.h
index 4f60be9..c653756 100644
--- a/passwordsync/passhand.h
+++ b/passwordsync/passhand.h
@@ -71,6 +71,7 @@ typedef list<PASS_INFO> PASS_INFO_LIST;
typedef list<PASS_INFO>::iterator PASS_INFO_LIST_ITERATOR;
void timeStamp(fstream* outFile);
+void wtimeStamp(wfstream* outFile);
int encrypt(char* plainTextBuf, int plainTextLen, char* cipherTextBuf, int cipherTextLen, int* resultTextLen);
int decrypt(char* cipherTextBuf, int cipherTextLen, char* plainTextBuf, int plainTextLen, int* resultTextLen);
diff --git a/passwordsync/passhook/passhook.cpp b/passwordsync/passhook/passhook.cpp
index 3218881..801b98f 100644
--- a/passwordsync/passhook/passhook.cpp
+++ b/passwordsync/passhook/passhook.cpp
@@ -56,8 +56,9 @@ NTSTATUS NTAPI PasswordChangeNotify(PUNICODE_STRING UserName, ULONG RelativeId,
{
PASS_INFO *newPassInfo = NULL;
HANDLE passhookThreadHandle;
- fstream outLog;
+ wfstream outLog;
DWORD waitRes;
+ int len;
// If UserName is NULL, just return STATUS_SUCCESS
if (UserName == NULL) {
@@ -65,41 +66,121 @@ NTSTATUS NTAPI PasswordChangeNotify(PUNICODE_STRING UserName, ULONG RelativeId,
}
// This memory will be freed in SavePasshookChange
- if ( newPassInfo = (PASS_INFO *) malloc(sizeof(PASS_INFO)) ) {
- // These get freed in SavePasshookChange by calling clearSet
- newPassInfo->username = (char*)malloc((UserName->Length / 2) + 1);
- if (Password != NULL) {
- newPassInfo->password = (char*)malloc((Password->Length / 2) + 1);
- } else {
- newPassInfo->password = (char*)malloc(1);
- }
- } else {
+ newPassInfo = (PASS_INFO *)calloc(1, sizeof(PASS_INFO));
+ if (NULL == newPassInfo) {
goto exit;
}
+ outLog.open("passhook.log", ios::out | ios::app);
// Fill in the password change struct
- if (newPassInfo->username && newPassInfo->password) {
- _snprintf(newPassInfo->username, (UserName->Length / 2), "%S", UserName->Buffer);
- newPassInfo->username[UserName->Length / 2] = '\0';
- if (Password != NULL) {
- _snprintf(newPassInfo->password, (Password->Length / 2), "%S", Password->Buffer);
- newPassInfo->password[Password->Length / 2] = '\0';
- } else {
- newPassInfo->password[0] = '\0';
+ /* Note: LPSTR == "char *" */
+ len = WideCharToMultiByte(CP_UTF8, 0 /* no flags */,
+ // Length is in bytes; assume UCS2
+ UserName->Buffer, UserName->Length/2,
+ newPassInfo->username, 0,
+ NULL, NULL);
+ if (len > 0) {
+ newPassInfo->username = (char*)malloc(len + 1);
+ if (NULL == newPassInfo->username) {
+ if(outLog.is_open()) {
+ wtimeStamp(&outLog);
+ outLog << "Failed to alloc mem for user " << UserName->Buffer
+ << "; error (" << GetLastError() << ")" << endl;
+ }
+ free(newPassInfo);
+ goto exit;
}
-
- // Backoff
- newPassInfo->backoffCount = 0;
-
- // Load time
- time(&(newPassInfo->atTime));
} else {
- // Memory error. Free everything we allocated.
- free(newPassInfo->username);
- free(newPassInfo->password);
+ newPassInfo->username = NULL;
+ if(outLog.is_open()) {
+ wtimeStamp(&outLog);
+ outLog << "Failed to calc mem for user " << UserName->Buffer
+ << "; error (" << GetLastError() << ")" << endl;
+ }
+ free(newPassInfo);
+ goto exit;
+ }
+ len = WideCharToMultiByte(CP_UTF8, 0 /* no flags */,
+ // Length is in bytes; assume UCS2
+ UserName->Buffer, UserName->Length/2,
+ newPassInfo->username, len+1,
+ NULL, NULL);
+ if (0 == len) {
+ if(outLog.is_open()) {
+ wtimeStamp(&outLog);
+ outLog << "Failed to convert user " << UserName->Buffer
+ << "; error (" << GetLastError() << ")" << endl;
+ }
free(newPassInfo);
goto exit;
}
+ newPassInfo->username[len] = '\0';
+ if (Password != NULL) {
+ len = WideCharToMultiByte(CP_UTF8, 0 /* no flags */,
+ // Length is in bytes; assume UCS2
+ Password->Buffer, Password->Length/2,
+ newPassInfo->password, 0,
+ NULL, NULL);
+ if (len > 0) {
+ newPassInfo->password = (char*)malloc(len + 1);
+ if (NULL == newPassInfo->password) {
+ if(outLog.is_open()) {
+ wtimeStamp(&outLog);
+ outLog << "Failed to alloc mem for password " << Password->Buffer
+ << "; error (" << GetLastError() << ")" << endl;
+ }
+ free(newPassInfo->username);
+ free(newPassInfo);
+ goto exit;
+ }
+ } else {
+ newPassInfo->password = NULL;
+ if(outLog.is_open()) {
+ wtimeStamp(&outLog);
+ outLog << "Failed to calc mem for password " << Password->Buffer
+ << "; error (" << GetLastError() << ")" << endl;
+ }
+ free(newPassInfo->username);
+ free(newPassInfo);
+ goto exit;
+ }
+ len = WideCharToMultiByte(CP_UTF8, 0 /* no flags */,
+ // Length is in bytes; assume UCS2
+ Password->Buffer, Password->Length/2,
+ newPassInfo->password, len+1,
+ NULL, NULL);
+ if (0 == len) {
+ if(outLog.is_open()) {
+ wtimeStamp(&outLog);
+ outLog << "Failed to convert password " << Password->Buffer
+ << "; error (" << GetLastError() << ")" << endl;
+ }
+ free(newPassInfo->username);
+ free(newPassInfo->password);
+ free(newPassInfo);
+ goto exit;
+ }
+ newPassInfo->password[len] = '\0';
+ } else {
+ newPassInfo->password = (char*)malloc(1);
+ if (NULL == newPassInfo->password) {
+ if(outLog.is_open()) {
+ wtimeStamp(&outLog);
+ outLog << "Failed to allocate for empty password."
+ << "; error (" << GetLastError() << ")" << endl;
+ }
+ free(newPassInfo->username);
+ free(newPassInfo);
+ goto exit;
+ }
+ newPassInfo->password[0] = '\0';
+ }
+
+ // Backoff
+ newPassInfo->backoffCount = 0;
+
+ // Load time
+ time(&(newPassInfo->atTime));
// Fire off a thread to do the real work
passhookThreadHandle = CreateThread(NULL, 0, SavePasshookChange, newPassInfo, 0, NULL);
@@ -114,21 +195,24 @@ NTSTATUS NTAPI PasswordChangeNotify(PUNICODE_STRING UserName, ULONG RelativeId,
// If we got the mutex, log the error, otherwise it's not safe to log
if (waitRes == WAIT_OBJECT_0) {
- outLog.open("passhook.log", ios::out | ios::app);
+ if(!outLog.is_open()) {
+ outLog.open("passhook.log", ios::out | ios::app);
+ }
if(outLog.is_open()) {
- timeStamp(&outLog);
+ wtimeStamp(&outLog);
outLog << "Failed to start thread. Aborting change for " << newPassInfo->username << endl;
}
- outLog.close();
-
// Release mutex
ReleaseMutex(passhookMutexHandle);
}
}
exit:
+ if(outLog.is_open()) {
+ outLog.close();
+ }
return STATUS_SUCCESS;
}
@@ -234,7 +318,9 @@ DWORD WINAPI SavePasshookChange( LPVOID passinfo )
}
// Close the log file before we release the mutex.
- outLog.close();
+ if(outLog.is_open()) {
+ outLog.close();
+ }
// Release the mutex for passhook.dat
ReleaseMutex(passhookMutexHandle);
diff --git a/passwordsync/passsync/syncserv.cpp b/passwordsync/passsync/syncserv.cpp
index bf3fde5..d6409cf 100644
--- a/passwordsync/passsync/syncserv.cpp
+++ b/passwordsync/passsync/syncserv.cpp
@@ -430,14 +430,15 @@ int PassSyncService::SyncPasswords()
timeStamp(&outLog);
outLog << "Multiple results not allowed: " << currentPassInfo->username << endl;
}
- else if(LDAP_SUCCESS == (bindRC = CanBind(dn, currentPassInfo->password)))
+ else if (LDAP_SUCCESS == (bindRC = CanBind(dn, currentPassInfo->password)))
{
if(logLevel > 0) {
timeStamp(&outLog);
outLog << "Password match, no modify performed: " << currentPassInfo->username << endl;
}
}
- else if(LDAP_INVALID_CREDENTIALS != bindRC)
+ else if ((LDAP_INVALID_CREDENTIALS != bindRC) &&
+ (LDAP_INAPPROPRIATE_AUTH != bindRC))
{
// password check failure.
/*
@@ -446,12 +447,16 @@ int PassSyncService::SyncPasswords()
* in the second round. The following modification invokes the
* server side's WinSync plugin to send the modify back, and this
* code is invoked as the second round. If the return code from
- * CanBind is not LDAP_INVALID_CREDENTIALS (e.g., LDAP_UNWILLING_
- * TO_PERFORM for the inactivated account), the second round Can-
- * Bind wound not return LDAP_SUCCESS even if the password is
- * correctly updated. That's said, if CanBind returns any error
- * other than LDAP_INVALID_CREDENTIALS, we should defer the pass-
- * word update.
+ * CanBind is not LDAP_INVALID_CREDENTIALS or LDAP_INAPPROPRIATE_
+ * AUTH (e.g., LDAP_UNWILLING_TO_PERFORM for the inactivated
+ * account), the second round CanBind wound not return LDAP_
+ * SUCCESS even if the password is correctly updated. That's
+ * said, if CanBind returns any error other than LDAP_INVALID_
+ * CREDENTIALS, we should defer the password update.
+ *
+ * Note: LDAP_INAPPROPRIATE_AUTH is returned when the entry has
+ * no userpassword and trying to auth with LDAP_AUTH_SIMPLE.
+ * This case, the password is to be sync'ed,
*/
timeStamp(&outLog);
outLog << "Checking password failed for remote entry: " << dn << endl;
10 years, 11 months