https://bugs.openldap.org/show_bug.cgi?id=10455
Issue ID: 10455
Summary: Allow handling of empty group in
memberof_saveMember_cb()
Product: OpenLDAP
Version: 2.6.12
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: overlays
Assignee: bugs(a)openldap.org
Reporter: roger.j.meier(a)gmx.ch
Target Milestone: ---
Created attachment 1117
--> https://bugs.openldap.org/attachment.cgi?id=1117&action=edit
Protect e_attrs with a NULL pointer test instead of an assert() to allow empty
groups
In slapd/overlays/memberof.c, the callback
memberof_saveMember_cb()
uses two assert statements for the sr_entry and its e_attrs pointer in
sequence. This makes the service abort on an empty group. If the use of
rs->sr_entry->e_attrs is just protected by a test of the e_attrs pointer, the
code does not abort and allows empty groups.
Please consider to add this patch to the official source.
It was now several month in production and did not lead to unexpected results.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10568
Issue ID: 10568
Summary: Client tools segfault when run without arguments
Product: OpenLDAP
Version: 2.7.0
Hardware: x86_64
OS: Linux
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: client tools
Assignee: bugs(a)openldap.org
Reporter: nzb_tuxxx(a)proton.me
Target Milestone: ---
When the default connection fails, several client tools call `strlen(ldapuri)`
while `ldapuri` is `NULL`.
Steps to reproduce:
1. Run `ldapadd`, `ldapdelete`, `ldapmodify`, `ldapmodrdn`, `ldappasswd`,
`ldapsearch`, `ldapvc`, or `ldapwhoami` without arguments.
2. Observe `Segmentation fault (core dumped)` and exit status 139.
References:
- Regression:
https://git.openldap.org/openldap/openldap/-/commit/37d677fb8d16b05a387c9f9…
- Downstream report:
https://gitlab.archlinux.org/archlinux/packaging/packages/openldap/-/work_i…
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10571
Issue ID: 10571
Summary: Asyncmeta's conn-ttl optional reset-interval argument
silently defaults to the TTL
Product: OpenLDAP
Version: 2.7.0
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: backends
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
mc->mc_conn_reset_interval is set to TTL if the 1 argument form is configured
(no value for <interval> provided) but as per manpage it should default to `1`
instead.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10576
Issue ID: 10576
Summary: modify dn is not logged when STATS2 is on
Product: OpenLDAP
Version: 2.7.0
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: slapd
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
ITS#9042 hid the line in the else branch, it should be outside the if with a
STATS|STATS2 filter.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10579
Issue ID: 10579
Summary: tlso_sb_{read,write} don't handle the opposite
condition
Product: OpenLDAP
Version: 2.7.0
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: lloadd
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
With non-blocking BIO (lloadd), a SSL_write can error out with
SSL_ERROR_WANT_READ and vice versa, e.g. at renegotiation or more points if TLS
1.3 is in place. Without knowing that, lloadd (or other applications if we ever
say non-blocking OpenSSL use is supported) cannot make the right decisions,
e.g. close a healthy connection.
Of course lloadd also needs to expect this situation and arm the correct
callback otherwise things get even worse.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10582
Issue ID: 10582
Summary: The method 'date -u -r ... %T' to print time periods
when testing is incorrectly implemented
Product: OpenLDAP
Version: 2.6.14
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: test suite
Assignee: bugs(a)openldap.org
Reporter: Peter_Dyballa(a)Web.DE
Target Milestone: ---
'date -u -r ... %T' works when "..." stands for a file name. Otherwise one
gets:
In tests/scripts/all the decision is made which date utility has to be
controlled:
# check for BSD vs GNU date
date -j >/dev/null 2>&1
RC=$?
if [ $RC -ne 0 ]; then
DATEOPT="-d @"
else
DATEOPT="-r "
fi
On Macs 'date -j' produces useful output (So 30 Aug 2026 18:57:39 CEST), so
it's decided to use -r on Macs – which implies that the argument following this
option is a file. And so date has to complain:
date: 0: No such file or directory
...
date: 23: No such file or directory
...
It might work to change the time() function become for example:
timer() {
if [ -n "$STARTTIME" ]; then
now=`date +%s`
delta=`expr $now - $STARTTIME`
touch $delta
date -u $DATEOPT $delta +%T
fi
}
For Macs it might work to patch tests/scripts/all to start with
gdate -j >/dev/null 2>&1
Then timer() would use -d @ which gdate and the macOS systems' date do
understand.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10578
Issue ID: 10578
Summary: libldap never clears OpenSSL error queue so
SSL_get_error() can misreport on OpenSSL <4.0
Product: OpenLDAP
Version: 2.7.0
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: libraries
Assignee: bugs(a)openldap.org
Reporter: ondra(a)mistotebe.net
Target Milestone: ---
SSL_get_error() needs the calling thread's error queue to be empty before the
SSL_* calls that could have produced one but we never make sure that's the
case. SSL_get_error() doesn't actually clear the error from the queue, so if a
SSL_* call returns an error on OpenSSL <4.0, it stays around as poison.
This can manifest e.g. as an otherwise healthy connection being suddenly
terminated with a reason that doesn't track.
We should just call ERR_clear_error() before every SSL_* call that can set it
to get something meaningful back.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10561
Issue ID: 10561
Summary: multiple logging.c minor issues
Product: OpenLDAP
Version: 2.6.13
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: slapd
Assignee: bugs(a)openldap.org
Reporter: dontbugme.relocate646(a)slmail.me
Target Milestone: ---
Created attachment 1185
--> https://bugs.openldap.org/attachment.cgi?id=1185&action=edit
servers/slapd/logging.c surprising behaviors
# OpenLDAP `slapd` log-file engine — observed bugs and pitfalls
This document lists defects and surprising behaviors identified by reading
`servers/slapd/logging.c` (the `logfile`, `logfile-format`, `logfile-only`
and `logfile-rotate` implementation) in this tree. All line references point to
that file.
> Scope: these concern the **internal** log file that `slapd` writes itself when
> `logfile <path>` is configured. They are independent of `rsyslogd`/`syslog-ng`.
---
## Bug 1 — `loglevel`/`olcLogLevel` messages are *not* written to the logfile
unless `logfile-only on`
### What happens
`slapd` maintains two separate diagnostic streams:
* the **debug stream** (`slap_debug`), fed by the `-d` command-line flag, and
* the **syslog stream** (`ldap_syslog`), fed by `loglevel`/`olcLogLevel` (and
`-s`).
The internal log file is written **only** from the debug stream. The actual
write is done in `slap_debug_print()`, which is the `LBER_OPT_LOG_PRINT_FN`
callback fired for every `ber_log*` message whose level passes `slap_debug`
(`logging.c:138` and `:222`). Messages that only pass `ldap_syslog` are emitted
through `syslog()` and never reach the file.
`logfile-only` controls this:
* `logfile-only off` (default): `slap_debug_print()` also writes to stderr
(`:135`), and syslog messages stay in syslog — **they never land in the
file**.
* `logfile-only on`: `slap_syslog_set()` ORs the syslog level into `slap_debug`
and zeroes `ldap_syslog` (`:571-581`, `:807-819`, `:593-600`), so syslog
messages now flow into the file — **but syslog itself is disabled**.
So there is **no configuration that writes *both* syslog and a complete log
file**. Setting `logfile` + `loglevel stats` is the trap most operators fall
into: stats go to syslog, and the file stays empty (unless you also used `-d`
or `logfile-only on`).
### How to reproduce
`slapd.conf` (or `cn=config` equivalent):
```
logfile /tmp/slapd.log
loglevel stats
# (no -d flag, no logfile-only)
```
1. Start `slapd -f slapd.conf -h "ldap://:3899/"` (do **not** pass `-d`).
2. Bind / search a few times.
3. Inspect the file:
```sh
cat /tmp/slapd.log # empty (or only the startup Versionstr line)
journalctl -t slapd # shows "conn=N op=M ... RESULT" stats lines
```
4. Stop, add `logfile-only on`, restart, repeat. Now:
```sh
cat /tmp/slapd.log # stats lines ARE present
journalctl -t slapd # stats lines are GONE (syslog disabled)
```
### Severity
High for operators expecting `logfile` + `loglevel` to mirror syslog. The
behavior is by design but undocumented as a limitation.
---
## Bug 2 — Stale PID in syslog-style log prefixes (`getpid()` captured before
`fork()`)
### What happens
When `logfile-format` is one of the syslog-style values
(`syslog-utc`/`syslog-localtime`/`rfc3339-utc`), the prefix string
`"<host> <prog>[<pid>]: "` is built **once**, at config-parse time, inside the
`CFG_LOGFILE_FORMAT` handler (`logging.c:852-856`):
```c
splen = sprintf( syslog_prefix, "%s %s %s[%d]: ", ..., serverName, getpid() );
```
`config_logging()` runs while `slapd` is still the original process. `slapd`
then daemonizes (`slapd_daemon()` forks), so the child that actually does the
logging has a **different PID** than the one baked into `syslog_prefix`.
Every line in the file therefore shows the pre-fork parent PID, not the PID of
the running daemon.
### How to reproduce
`slapd.conf`:
```
logfile /tmp/slapd.log
logfile-format syslog-localtime
loglevel stats
```
1. Start `slapd` in daemon mode (default): `slapd -f slapd.conf -h
"ldap://:3899/"`.
2. Find the real daemon PID:
```sh
pidof slapd
cat /run/slapd/slapd.pid # or wherever pidfile points
```
3. Trigger a line (any search) and look at the prefix in the file:
```sh
head -3 /tmp/slapd.log
# e.g. Aug 05 10:40:12 host slapd[1234]: conn=1 ...
```
`1234` is the PID of the short-lived parent, not the daemon PID printed by
`pidof slapd`.
### Severity
Medium. Cosmetic for single-instance setups, but misleading for log analysis /
process correlation and for systems that run `slapd` under a supervisor that
expects the logged PID to match the supervised process.
---
## Bug 3 — `logfile-format default` is identical to `logfile-format debug`
### What happens
The log-file header is only rebuilt when `logfile_format > LFMT_DEBUG`
(`logging.c:185`). For `LFMT_DEFAULT` (value `0`) and `LFMT_DEBUG` (value `1`)
the `iov[0]` debug prefix (`"%lx.<frac> <pthread> "`, built at `:130`) is used
verbatim. So:
* `default` → raw `epoch.hex <threadptr> ` prefix, **no** date, **no**
hostname,
**no** PID;
* `debug` → exactly the same.
The name `default` suggests a "normal" syslog-like line, but it is just the
`-d`-style debugging prefix. The only formats that actually add a timestamp /
host / PID header are `syslog-utc`, `syslog-localtime` and `rfc3339-utc`.
### How to reproduce
```
logfile /tmp/default.log
logfile-format default
loglevel stats
# (separate run)
logfile /tmp/debug.log
logfile-format debug
loglevel stats
```
Run `slapd`, trigger one operation in each, then `diff`:
```sh
head -1 /tmp/default.log; head -1 /tmp/debug.log # byte-identical prefixes
```
### Severity
Low. Documentation/naming clarity issue; can surprise anyone expecting
human-readable timestamps from the default format.
---
## Bug 4 — Rotation numbered-shift runs outside the mutex (lost backups under
load)
### What happens
Rotation is split in two:
1. Under `logfile_mutex` (`:140-183`): the current file is renamed to
`<path>.tmp` (`:147-148`) and a fresh file is reopened (`:166`).
2. **After** the mutex is released (`:227`), the numbered-shift loop runs
(`:229-238`): it renames `<path>.tmp` → `<path>.NN` and shifts older
`<path>.NN` → `<path>.N(N+1)`.
Because step 2 executes outside the lock, two (or more) threads that both
tripped the size/age threshold can interleave:
```
T1: under lock -> rename current -> .tmp ; reopen ; unlock
T2: under lock -> rename NEW current -> .tmp ; reopen ; unlock
T1: outside lock-> rename .tmp -> .NN (this .tmp is actually T2's rotated
file)
T2: outside lock-> rename .tmp -> .NN (no .tmp exists anymore -> rename()
fails,
the backup T2 meant to keep is lost)
```
Consequences under heavy concurrent logging near the rotation threshold:
* a rotated backup can be silently overwritten / lost, and
* `rename()` is called on a `.tmp` that no longer exists (returns `-1`,
ignored).
The trigger-to-`.tmp` step is safe (under the lock) but the hand-off to the
outside-lock shift is racy because the shared `.tmp` name is reused by every
rotation event.
### How to reproduce (best-effort, not deterministic)
```
logfile /tmp/slapd.log
logfile-format debug
logfile-rotate 5 1 0 # 5 backups, 1 MB size limit, no age limit
loglevel any # enable verbose categories
```
Drive a very high-volume debug stream so the file crosses 1 MB repeatedly in a
short window (e.g. `loglevel sync stats packets` plus a busy replication
session, or a tight loop of anonymous binds). Then list backups:
```sh
ls -la /tmp/slapd.log*
```
Expected: `.01` … `.05` present and strictly ordered by age.
Observed under load: gaps (e.g. `.01 .02 .04 .05` with `.03` missing) or a
rotation where the oldest retained copy is newer than it should be, indicating
a backup was clobbered by a racing rotation.
> Note: because the race is timing-dependent, run the load several times; the
> failure is intermittent, which is itself the signature of a lock-ordering bug.
### Severity
Low-to-medium. Only matters with `logfile-rotate` enabled and very high log
volume. Data-loss is of rotated *backups*, not of the live log.
---
## Bug 5 — Age-based rotation uses inode change time, not file create/modify
time
### What happens
When a file is (re)opened, the rotation "birth" timestamp is taken from
`st_ctime` (`logging.c:287`):
```c
logfile_fcreated = st.st_ctime; /* not strictly true but close enough */
```
The comment admits the approximation. `st_ctime` changes on *any* inode
metadata change (chmod, chown, rename, truncate, `touch -c`), not just content
creation. Age-based rotation (`logfile-rotate <max> <MB> <hours>`) therefore
measures the interval since the last inode-changing event, which can be reset
by an external tool (logrotate `copytruncate`, backup, permission change) and
produce an unexpectedly early or late rotation.
### How to reproduce
```
logfile /tmp/slapd.log
logfile-format debug
logfile-rotate 3 0 1 # rotate every 1 hour (no size limit)
loglevel stats
```
1. Start `slapd`; note the time.
2. Before the hour elapses, touch the inode metadata externally:
```sh
touch /tmp/slapd.log # updates ctime (open with O_TRUNC not needed)
```
3. Watch rotation: it can fire based on the *touch* time rather than the
daemon's own start/last-write time, because `logfile_fcreated` reflects
`ctime`.
### Severity
Low. Edge-case affecting operators who let an external tool also touch the
logfile.
---
## Summary table
| # | Bug | Config affected | Effect | Can lose data? |
|---|-----|-----------------|--------|----------------|
| 1 | `loglevel` not written to file unless `logfile-only on` |
`logfile`+`loglevel` | file misses syslog-level messages | no (silent gap) |
| 2 | Stale PID in syslog-style prefixes | `logfile-format
syslog-*`/`rfc3339-*` | wrong `[pid]` in every line | no |
| 3 | `default` == `debug` output | `logfile-format default` | no
timestamp/host/pid header | no |
| 4 | Rotation shift outside mutex | `logfile-rotate` under load |
lost/overwritten backups | yes (backups only) |
| 5 | Age rotation uses `ctime` | `logfile-rotate … <hours>` | wrong rotation
timing | no |
---
## Workarounds
* To get `loglevel` content in the file, use `logfile-only on` **and** accept
that native syslog logging is then disabled — or run `slapd -d <level>`
instead of `loglevel`, or keep `rsyslogd` as the file writer.
* For correct per-line PID/timestamps, prefer `logfile-format rfc3339-utc`
(still has the stale-PID issue from Bug 2, but at least a real timestamp).
* Avoid relying on `logfile-rotate` for audit-grade retention under very high
log volume; use an external log rotator that copies and truncates, or pipe to
`rsyslogd`.
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10577
Issue ID: 10577
Summary: Memory leak in client-side libldap response handling
when a malformed BER message causes an error.
Product: OpenLDAP
Version: 2.6.8
Hardware: x86_64
OS: Linux
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: client tools
Assignee: bugs(a)openldap.org
Reporter: thetrenshow157(a)gmail.com
Target Milestone: ---
Created attachment 1195
--> https://bugs.openldap.org/attachment.cgi?id=1195&action=edit
Reproduction script
During client-side libldap fuzzing, a memory leak was found when processing a
malformed BER response.
If a response contains a valid message ID matching an outstanding request,
`ldap_find_request_by_msgid()` increments the `LDAPRequest` reference count. If
the following TLV declares a length larger than the remaining BER data,
`ber_peek_tag()` returns `LBER_ERROR` and `try_read1msg()` returns `-1` without
releasing the acquired request reference.
As a result, the `LDAPRequest` and its associated allocations are leaked.
The attached reproducer triggers the issue with a malformed BindResponse, but
the issue is not specific to the request type.
The Valgrind log was collected with OpenLDAP 2.6.8, but the memory leak is
still reproducible on the latest development branch. Although such a malformed
response is not expected from a compliant server, it would still be better to
handle this error path without leaking memory. I have attached the reproducer
script and the Valgrind log to this message.
Valgrind log:
==307307== Memcheck, a memory error detector
==307307== Copyright (C) 2002-2024, and GNU GPL'd, by Julian Seward et al.
==307307== Using Valgrind-3.26.0 and LibVEX; rerun with -h for copyright info
==307307== Command: ldapsearch -x -H ldap://127.0.0.1:37095/ -D cn=Directory\
Manager -w password -b dc=example,dc=com -s base (objectClass=*) -o
nettimeout=2 -l 2
==307307==
ldap_result: Can't contact LDAP server (-1)
==307307==
==307307== HEAP SUMMARY:
==307307== in use at exit: 4,290 bytes in 4 blocks
==307307== total heap usage: 165 allocs, 161 frees, 106,847 bytes allocated
==307307==
==307307== 4,276 (136 direct, 4,140 indirect) bytes in 1 blocks are definitely
lost in loss record 4 of 4
==307307== at 0x48664A4: calloc (vg_replace_malloc.c:1678)
==307307== by 0x48E7A4C: ber_memcalloc_x (memory.c:283)
==307307== by 0x48AA75A: ldap_send_server_request (request.c:349)
==307307== by 0x48AAD8F: ldap_send_initial_request (request.c:169)
==307307== by 0x489B296: ldap_sasl_bind (sasl.c:164)
==307307== by 0x400F226: tool_bind (common.c:1593)
==307307== by 0x400593A: main (ldapsearch.c:1109)
==307307==
==307307== LEAK SUMMARY:
==307307== definitely lost: 136 bytes in 1 blocks
==307307== indirectly lost: 4,140 bytes in 2 blocks
==307307== possibly lost: 0 bytes in 0 blocks
==307307== still reachable: 14 bytes in 1 blocks
==307307== suppressed: 0 bytes in 0 blocks
==307307== Reachable blocks (those to which a pointer was found) are not shown.
==307307== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==307307==
==307307== For lists of detected and suppressed errors, rerun with: -s
==307307== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
--
You are receiving this mail because:
You are on the CC list for the issue.
https://bugs.openldap.org/show_bug.cgi?id=10563
Issue ID: 10563
Summary: ldap_count_message() returns '1' even with empty
LDAPMessage as input.
Product: OpenLDAP
Version: 2.6.13
Hardware: All
OS: All
Status: UNCONFIRMED
Keywords: needs_review
Severity: normal
Priority: ---
Component: libraries
Assignee: bugs(a)openldap.org
Reporter: feh(a)fehcom.de
Target Milestone: ---
Source: libldap/messages.c
The function
int ldap_count_messages( LDAP *ld, LDAPMessage *chain )
given *chain is NULL will return a '1' as result.
Line numbers included:
49 int
50 ldap_count_messages( LDAP *ld, LDAPMessage *chain )
51 {
52 int i;
53
54 assert( ld != NULL );
55 assert( LDAP_VALID( ld ) );
56
57 for ( i = 0; chain != NULL; chain = chain->lm_chain ) {
58 i++;
59 }
60
61 return( i );
62 }
It would be sufficient to test the LDAP message *chain in the following way
before the for loop is executed:
line 56: if (!chain && !*chain) return ( 0 );
--eh.
--
You are receiving this mail because:
You are on the CC list for the issue.