Skip to content

Docker image: setup.sh passes ROOT_PASSWORD unquoted to ldapmodify, so bootstrap LDIFs are silently skipped for a password with spaces #1093

Description

@vharseko

Problem

bootstrap/setup.sh loads the optional LDIF files from /opt/opendj/bootstrap/schema/ and /opt/opendj/bootstrap/data/ with an unquoted password (setup.sh#L88, #L105):

/opt/opendj/bin/ldapmodify -D "$ROOT_USER_DN" -h localhost -p $PORT -w $ROOT_PASSWORD -f $file

A ROOT_PASSWORD that contains whitespace is split into several arguments, and one that contains *, ? or [ is subject to glob expansion. The bind then fails and the file is skipped. What that leads to depends on the image:

  • the released 5.1.2 image (reproduced below) reports itself healthy with the data missing, and the only trace is one line in the log;
  • on master, since Report the OpenDJ container healthy only once its bootstrap has succeeded #898, the exit status of setup.sh is that of its last command: a failed bind on the last data LDIF keeps the container from ever turning healthy, while a failed bind on a schema LDIF, or on an earlier data LDIF, is still skipped silently. The loads are meant to be tolerant (see the header of setup.sh); with --continueOnError, a refused entry leaves the exit status at 0, a failed bind does not.

Reproduced with openidentityplatform/opendj:latest (2026-07-17):

mkdir bdata
printf 'dn: ou=probe,dc=example,dc=com\nobjectClass: organizationalUnit\nou: probe\n' > bdata/10-probe.ldif
docker run -d --name sp -e ROOT_PASSWORD='two words' -e ADD_BASE_ENTRY=--addBaseEntry \
  -v "$PWD/bdata:/opt/opendj/bootstrap/data:ro" openidentityplatform/opendj:latest
# after it is healthy:
docker logs sp | grep -A1 'Loading /opt/opendj/bootstrap/data'
# Loading /opt/opendj/bootstrap/data/10-probe.ldif ...
# The LDAP bind request failed: 49 (Invalid Credentials)
docker exec sp /opt/opendj/bin/ldapsearch -h localhost -p 1389 -D "cn=Directory Manager" -w 'two words' \
  -b ou=probe,dc=example,dc=com -s base "(objectClass=*)" 1.1
# The LDAP search request failed: 32 (No Such Entry)

setup, dsconfig and import-ldif in the same script quote the password and are not affected.

Expected

Any password that setup accepts works for the LDIF loads too. The password is not passed on a command line at all: every tool used by the script has a file-based variant (setup --rootUserPasswordFile, dsconfig / import-ldif --bindPasswordFile, ldapmodify -j), which also keeps it out of /proc/<pid>/cmdline while the bootstrap runs. $file is quoted as well.

Also: pre-encoded passwords and ADMIN_PORT

Found while reproducing. The dsconfig set-password-policy-prop call that allows pre-encoded passwords before the data LDIFs are loaded names no host or port, so it goes to 4444 whatever ADMIN_PORT the server listens on. With a non-default ADMIN_PORT it fails (Unable to connect to the server at "localhost" on port 4444, not checked), and every entry of the data LDIFs that carries a pre-encoded password is refused (19 (Constraint Violation): Pre-encoded passwords are not allowed for the password attribute userPassword) while the container reports itself healthy. Checked with -e ADMIN_PORT=5444 on an image whose dsconfig call is as on master but whose password handling was already fixed, so that the binds themselves succeed.

Notes

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugdata-lossData integrity / loss of entriesdockersecuritySecurity fixes / CodeQL code-scanning alerts

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions